服务器端代码:#include\ "myhead.h"\n\nstruct thread_pool *pool = NULL; //线程池结构体指针\npclient_connfd cli = NULL; //已连接套接字数组结构体指针\npclient_info head = NULL; //客户端信息链表结构体指针\nint totaluser; //总在线用户数\n\n//任务函数\nvoid *my_task(void *arg)\n{\n pthread_detach(pthread_self()); //设置线程结束后自动回收资源\n\n // printf("123\n");\n char buf[100]; //接收缓冲区\n int ret = 0; //是否接收到数据标志位\n char *divide = ":"; //分隔符,分开收到数据的名字和内容\n\n // printf("000\n");\n pclient_info m = (pclient_info)arg;\n\n // printf("m->connfd:%d\n",m->connfd);\n // printf("m->client_name:%s\n",m->client_name);\n // printf("111\n");\n while (1)\n {\n //连接成功,开始接收数据\n bzero(buf, sizeof(buf));\n ret = recv(m->connfd, buf, sizeof(buf), 0); //大于0说明接收到了数据\n // if(ret==-1)//5s内无数据\n // {\n // printf("已超时\n");\n // }\n // printf("ret:%d\n",ret);\n if (ret > 0) //5s内有数据\n {\n printf("%s\n", buf); //打印收到的内容\n\n //将收到的信息转发给所有客户端\n for (pclient_info h = head->next; h != NULL; h = h->next) //将已经存入的用户名发送给用户端,来确保不会同名\n {\n if (h->connfd != m->connfd) //不发送给自己\n {\n send(h->connfd, buf, strlen(buf), 0);\n }\n }\n\n //char *p=strtok(buf,divide);//以冒号分割,得到前面的名字\n //p=strtok(NULL,buf);//获取冒号后的发送内容\n char p = strtok(buf, divide);\n\n / 继续获取其他的子字符串 */\n while (p != NULL)\n {\n p = strtok(NULL, divide);\n\n if (p != NULL && strncmp(p, "quit", strlen(p)) == 0) //客户端输入quit说明该客户端想要下线\n {\n if (strlen(p) == 4)\n {\n printf("%s已下线\n", m->client_name);\n printf("(当前在线用户数:%d)\n", --totaluser);\n close(m->connfd);\n delete_clientnode(head, m->client_IP); //从链表中删除下线的客户端\n }\n }\n }\n }\n }\n}\n\nint main(int argc, char *argv[])\n{\n //初始化线程池\n pool = malloc(sizeof(thread_pool));\n init_pool(pool, 0); //初始化线程池\n\n //初始化已连接套接字数组\n cli = init_connfdaddr();\n\n //初始化客户端结构体链表\n head = init_clientlist();\n\n //创建套接字\n int socket_fd = socket(AF_INET, SOCK_STREAM, 0);\n printf("socket_fd:%d\n", socket_fd);\n\n //绑定\n struct sockaddr_in server_addr;\n socklen_t len = sizeof(server_addr); //结构体长度\n bzero(&server_addr, len);\n\n server_addr.sin_family = AF_INET; //地址族\n server_addr.sin_port = htons(atoi(argv[1])); //端口号\n server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址\n bind(socket_fd, (struct sockaddr *)&server_addr, len);\n\n //设置监听套接字\n listen(socket_fd, 60); //可同时监听60个客户端\n\n //添加非阻塞属性(给socket_fd)\n int state;\n state = fcntl(socket_fd, F_GETFL);\n state |= O_NONBLOCK; //在原来的基础上再添加一个非阻塞属性\n fcntl(socket_fd, F_SETFL, state);\n\n struct sockaddr_in client_addr; //客户端结构体\n bzero(&client_addr, len);\n\n int tmp; //是否成功添加到数组中标志位\n char buf_name[50]; //客户端用户名\n\n //接收数据\n while (1)\n {\n bzero(buf_name, sizeof(buf_name));\n //等待客户端连接\n int connfd = accept(socket_fd, (struct sockaddr *)&client_addr, &len); //一直阻塞直到有客户端连入\n // printf("connfd:%d\n",connfd);\n if (connfd > 0) //表示有客户端连入\n {\n // //设置非阻塞属性\n // state=fcntl(connfd,F_GETFL);\n // state|=O_NONBLOCK;\n // fcntl(connfd,F_SETFL,state);\n\n //设置套接字属性为超时接收(给connfd)\n // struct timeval v;\n // v.tv_sec=10;//设置每次5秒接收时间\n // v.tv_usec=0;\n\n // setsockopt(connfd,SOL_SOCKET,SO_RCVTIMEO,&v,sizeof(v));//设置套接字超时接收属性\n\n if (totaluser >= 60) //为-1表示数组满了,加入失败\n {\n printf("可连入服务器端的客户端数量已满,无法连接\n");\n close(connfd);\n continue;\n }\n\n recv(connfd, buf_name, sizeof(buf_name), 0); //接收客户端的用户名\n\n // for(plient_info h=head->next;h!=NULL;h=h->next)//将已经存入的用户名发送给用户端,来确保不会同名\n // {\n // send(connfd,h->client_name,strlen(h->client_name),0);\n // recv(connfd,buf_name,sizeof(buf_name),0);//接收客户端的用户名\n // }\n\n printf("connfd:%d\n", connfd);\n printf("新连入的用户名为:%s\n", buf_name);\n printf("新连入的IP为:%s\n", inet_ntoa(client_addr.sin_addr));\n printf("(当前在线用户数:%d)\n", ++totaluser);\n\n if (find_nameclientnode(head, buf_name) == NULL && find_IPclientnode(head, inet_ntoa(client_addr.sin_addr)) == NULL) //等于NULL说明链表中没有存入该客户端(按名字)\n {\n new_clientnode(head, buf_name, inet_ntoa(client_addr.sin_addr), connfd); //将该客户端的名字与IP号插入到链表中\n print_clientlist(head);\n }\n\n pclient_info p = find_IPclientnode(head, inet_ntoa(client_addr.sin_addr));\n\n //新客户端连入,开辟一条新线程\n add_thread(pool, 1);\n add_task(pool, my_task, (void *)p);\n }\n }\n\n //关闭套接字\n close(socket_fd);\n\n return 0;\n}\n\n客户端代码:\n#include\ "myhead.h"\n\nint main(int argc, char *argv[])\n{\n\n //创建套接字\n int socket_fd = socket(AF_INET, SOCK_STREAM, 0);\n printf("sockfd = %d\n", socket_fd);\n\n\n //连接服务器端\n struct sockaddr_in server_addr;\n socklen_t len = sizeof(server_addr);\n bzero(&server_addr, len);\n server_addr.sin_family = AF_INET; //地址族\n server_addr.sin_port = htons(atoi(argv[2])); //服务器端端口号\n inet_pton(AF_INET, argv[1], &server_addr.sin_addr); //服务器端ip地址\n\n connect(socket_fd, (struct sockaddr *)&server_addr, len); //套接字连接客户端\n\n //输入客户端用户名\n char bufname[50]; //客户端名字\n bzero(bufname, sizeof(bufname));\n printf("请输入用户名:");\n scanf("%s", bufname);\n send(socket_fd, bufname, strlen(bufname), 0);\n\n // char bufback[50];\n\n // while(strncmp(bufname,bufback,strlen(bufname)!=0))\n // {\n // bzero(bufback,sizeof(bufback));\n // recv(socket_fd,bufback,sizeof(bufback),0);//接收客户端的用户名\n // if(strncmp(bufname,bufback,strlen(bufname)==0))\n // {\n // printf("用户名已存在,请重新输入\n");\n // printf("请输入用户名:");\n // scanf("%s",bufname);\n // send(socket_fd,bufname,strlen(bufname),0);\n // }\n // }\n\n char buf[50]; //发送缓冲区\n char buf1[100]; //拼接字符串后存入的数组\n char bufall[100]; //群聊接收缓冲区\n int ret1 = 0; //客户端是否接收成功标志位\n\n while (1)\n {\n bzero(buf, sizeof(buf));\n bzero(buf1, sizeof(buf1));\n bzero(bufall, sizeof(bufall));\n printf("请输入要送发的内容:");\n scanf("%s", buf);\n sprintf(buf1, "%s:%s", bufname, buf);\n // sprintf(buf1,"张三:%s",buf);\n send(socket_fd, buf1, strlen(buf1), 0);\n ret1 = recv(socket_fd, bufall, sizeof(bufall), 0);\n printf("ret1:%d\n", ret1);\n if (ret1 > 0)\n {\n printf("%s\n", bufall);\n }\n printf("strlenbufall:%ld\n", strlen(bufall));\n if (strncmp(buf, "quit", strlen(buf)) == 0)\n {\n if (strlen(buf) == 4)\n {\n break;\n }\n }\n }\n\n //关闭套接字\n close(socket_fd);\n\n return 0;\n

C语言实现的基于线程池的简易聊天室服务器端与客户端代码

原文地址: https://www.cveoy.top/t/topic/jqzf 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录