Linux下C语言多线程,网络通信简单聊天程序
- 格式:docx
- 大小:26.26 KB
- 文档页数:8
/** server.c** Created on: 2012-6-15* Author: root*/#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <sys/types.h>#include <error.h>#include<netinet/in.h>#define PORT 7999#define MAX_NUM 3 //client连接最大个数#define MAX_CLIENT 15#define MAX_SIZE 1024pthread_rwlock_t idx_lock, wait_lock;//client 信息typedef struct _client {int sockfd;char name[20];pthread_t pid;int flg;} c_client;c_client client[MAX_CLIENT];//定义client;//等待的clientstruct _client_ {int sockfd;char name[20];pthread_t pid;struct _client_ *next;};typedef struct _client_ c_client_c;c_client_c *head = NULL;c_client_c *temp_c1 = NULL, *temp_c2 = NULL;//等待的//初始化client信息void init_client() {int i = 0;for (i = 0; i < MAX_CLIENT; i++) {client[i].sockfd = -1;memset(client[i].name, 0, 20);client[i].pid = -1;client[i].flg = -1;}}//查找结构体数组中sockfd为-1的下标值int find_fd(c_client *client) {int i = 0;while (i < MAX_NUM) {// printf("====%d\n",client[i].sockfd);if (client[i].sockfd == -1)return i;i++;}return -1;}//判断登录格式int logform(char *buf) {char *p = strstr(buf, "LOGIN\r\n");int n = strlen(buf);char *q = p + n - 4;if (p != NULL && p + 7 != q && strcmp(q, "\r\n\r\n") == 0)return 1;elsereturn 0;}int cmpname(char *buf, c_client *p_client) {int i = 0;char *p = strtok(buf + 7, "\r\n\r\n");while (client[i].sockfd != -1 && client[i].sockfd != p_client->sockfd && i < MAX_NUM) {if (strcmp(client[i].name, p) == 0)return 0;i++;}return 1;}//SHOWvoid showuser(c_client *p_client) {int i = 0;char buf[1024] = { 0 };strcpy(buf, "200\r\n");for (i = 0; i < MAX_NUM; i++) {if (client[i].sockfd != -1) {sprintf(buf + strlen(buf), "%s\r\n", client[i].name);}}sprintf(buf + strlen(buf), "\r\n");send(p_client->sockfd, buf, strlen(buf), 0);}//ALLvoid sendto_all(c_client *p_client, char *buf) {int i = 0;char sendbuf[1024] = { 0 };sprintf(sendbuf, "AFROM\r\n%s\r\n%s", p_client->name, buf + 5);for (i = 0; i < MAX_NUM; i++) {if (client[i].sockfd != -1 && client[i].flg != -1)if(send(client[i].sockfd, sendbuf, strlen(sendbuf), 0) <= 0){printf("send errrrrr\n");exit(1);}}}int findname(char *name) {int i = 0;for (i = 0; i < MAX_NUM; i++) {if (client[i].sockfd != -1 && strcmp(client[i].name, name) == 0) return client[i].sockfd;}return 0;}//TOvoid sendto_one(c_client *p_client, char *buf) {int i = 0;char sendbuf[1024] = { 0 };char name[20] = { 0 };char *p = strtok(buf + 4, "\r\n");//TO\r\n:4个字符后取出\r\n前的名字strcpy(name, p);int sock = findname(name);if (!sock) {sprintf(sendbuf, "ERROR2\r\n%s用户不存在\r\n\r\n", name);send(p_client->sockfd, sendbuf, strlen(sendbuf), 0);} else {sprintf(sendbuf, "FROM\r\n%s\r\n%s", p_client->name, buf + 4 + strlen( name) + 2);if(send(sock, sendbuf, strlen(sendbuf), 0)<=0){printf("send errrrrr\n");exit(1);}}}void pthread_fun(void* cclient);//quitvoid quit(c_client *p_client){int i=0;int idx;char buf[1024] = {0};c_client_c *temp;printf("--%s退出聊天室\n",p_client->name);close(p_client->sockfd);p_client->sockfd = -1;p_client->pid = -1;p_client->flg = -1;sprintf(buf,"NOTICE1\r\n%s退出聊天室\r\n\r\n",p_client->name);memset(p_client->name,0,20);for(i=0;i<MAX_NUM;i++){if(client[i].sockfd != -1 && client[i].flg != -1)send(client[i].sockfd,buf,strlen(buf),0);}if(head != NULL && head->next != NULL){memset(buf,0,1024);pthread_rwlock_rdlock(&idx_lock);idx = find_fd(client);pthread_rwlock_unlock(&idx_lock);client[idx].sockfd = head->next->sockfd;pthread_rwlock_wrlock(&wait_lock);temp = head->next;head->next = head->next->next;free(temp);pthread_rwlock_unlock(&wait_lock);sprintf(buf,"NOTICE\r\n您已被唤醒,请继续操作\r\n\r\n");send(client[idx].sockfd,buf,strlen(buf),0);if (pthread_create(&client[idx].pid, NULL, (void *)pthread_fun,(void *) &client[idx]) != 0) {perror("pthread_create");exit(1);}pthread_detach(client[idx].pid);}}void pthread_fun(void* cclient) {c_client *p_client = (c_client *) cclient;char buf[MAX_SIZE] = { 0 };char sendbuf[1024] = { 0 };int i, n;char *p;sprintf(sendbuf, "%s", "NOTICE\r\n通讯通道开启\r\n\r\n");if (send(p_client->sockfd, sendbuf, strlen(sendbuf), 0) <= 0) {printf("send err\n");}memset(sendbuf, 0, 1024);while (1) {memset(buf, 0, MAX_SIZE);n = recv(p_client->sockfd, buf, sizeof(buf) - 1, MSG_NOSIGNAL);if (n <= 0) {close(p_client->sockfd);p_client->sockfd = -1;break;}if (logform(buf)) {if (cmpname(buf, p_client) == 0) {send(p_client->sockfd, "ERROR\r\n用户名重复\r\n\r\n", 26, 0);continue;} else {p_client->flg = 1;p = strtok(buf + 7, "\r\n\r\n");strcpy(p_client->name, p);sprintf(sendbuf, "100\r\n%s\r\n\r\n", p_client->name);send(p_client->sockfd, sendbuf, sizeof(sendbuf), 0);printf("%s进入聊天室\n", p_client->name);for (i = 0; i < MAX_NUM; i++) {if (client[i].sockfd != -1 && client[i].sockfd!= p_client->sockfd && client[i].flg != -1)send(client[i].sockfd, sendbuf, sizeof(sendbuf), 0);}memset(sendbuf, 0, 1024);while (1) {memset(buf, 0, MAX_SIZE);if ((n = recv(p_client->sockfd, buf, MAX_SIZE, 0)) <= 0) {perror("recv err");break;}// printf("recv=%s\n",buf);if ((p = strstr(buf, "\r\n\r\n")) != NULL && *(p + 4)== '\0') {if (!strncmp(buf, "SHOW\r\n\r\n", 8)) {showuser(p_client);//客户端执行show后,发送给客户端已连接的用户continue;}if (!strncmp(buf, "ALL\r\n", 5)) {sendto_all(p_client, buf);continue;}if (!strncmp(buf, "TO\r\n",4)) {sendto_one(p_client, buf);continue;}if (!strncmp(buf, "QUIT\r\n\r\n", 8))quit(p_client);// break;pthread_exit(NULL);} else {send(p_client->sockfd, "ERROR\r\n信息不符合协议要求\r\n\r\n",38, 0);}}}} else {send(p_client->sockfd, "ERROR\r\n未登录,请您登录再进行其他操作\r\n\r\n", 56, 0);}}pthread_exit(NULL);}int main() {int ser_sockfd, clt_sockfd;struct sockaddr_in addr;int idx;char buf[1024] = { 0 };// pthread_rwlock_t idx_lock,wait_lock;pthread_rwlock_init(&idx_lock, NULL);pthread_rwlock_init(&wait_lock, NULL);init_client();//创建服务器sockfdif ((ser_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {perror("socket");exit(1);}//设置服务器网络地址bzero(&addr, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(PORT);addr.sin_addr.s_addr = htonl(INADDR_ANY);//设置端口可重用int opt = 1;setsockopt(ser_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));//将套接字绑定到服务器的网络地址上if (bind(ser_sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { perror("bind");exit(1);}printf("bind success\n");//监听连接请求--监听队列长度为10if (listen(ser_sockfd, 10) == -1) {perror("listen");exit(1);}printf("listen success\n");while (1) {if ((clt_sockfd = accept(ser_sockfd, NULL, NULL)) == -1) {perror("accept");exit(1);}pthread_rwlock_rdlock(&idx_lock);idx = find_fd(client);// printf("idx=%d\n",idx);pthread_rwlock_unlock(&idx_lock);if (idx != -1) { //连接末满client[idx].sockfd = clt_sockfd;if (pthread_create(&client[idx].pid, NULL,(void *) pthread_fun,(void *)&client[idx]) != 0) {perror("pthread_create");exit(1);}pthread_detach(client[idx].pid);} else { //连接已满,等待temp_c1 = (c_client_c *) malloc(sizeof(c_client_c));temp_c1->sockfd = clt_sockfd;temp_c1->next = NULL;pthread_rwlock_wrlock(&wait_lock);if (head == NULL) {head = (c_client_c *) malloc(sizeof(c_client_c));head->next = temp_c1;} else {for (temp_c2 = head; temp_c2->next != NULL; temp_c2= temp_c2->next);temp_c2->next = temp_c1;}pthread_rwlock_unlock(&wait_lock);memset(buf, 0, 1024);sprintf(buf, "NOTICE\r\n服务器已满,请等候\r\n\r\n");//客户端接受则等待if (send(temp_c1->sockfd, buf, strlen(buf), 0) <= 0) {printf("sendr err\n");}}}}/** client.c** Created on: 2012-6-18* Author: root*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <unistd.h>#include <sys/types.h>#include <pthread.h>#include <netinet/in.h>#include <error.h>#include <arpa/inet.h>#include <termios.h>#define MAX_SIZE 1024#define PORT 7999static int FLAGE = -1;char name[20] = {0};void fun_show(int sockfd){char sendbuf[256] = {0};sprintf(sendbuf,"SHOW\r\n\r\n");if(send(sockfd,sendbuf,strlen(sendbuf),0)<=0){ printf("send err\n");close(sockfd);exit(1);}}void fun_all(int sockfd){char sendbuf[MAX_SIZE] = {0};sprintf(sendbuf,"ALL\r\n",5);printf("输入发送的内容:\n");scanf("%s",sendbuf+5);sprintf(sendbuf+strlen(sendbuf),"\r\n\r\n");if(send(sockfd,sendbuf,strlen(sendbuf),0) <= 0){ printf("send err\n");close(sockfd);exit(1);}}void fun_one(int sockfd){char sendbuf[MAX_SIZE] = {0};char name3[20] = {0};printf("输入聊天对象:");scanf("%s",name3);sprintf(sendbuf,"TO\r\n%s\r\n",name3);printf("输入聊天内容:\n");scanf("%s",sendbuf+strlen(sendbuf));sprintf(sendbuf+strlen(sendbuf),"\r\n\r\n");if(send(sockfd,sendbuf,strlen(sendbuf),0) <= 0){printf("send err\n");close(sockfd);exit(1);}}void fun_quit(int sockfd){char sendbuf[256] = "QUIT\r\n\r\n";if(send(sockfd,sendbuf,strlen(sendbuf),0) <= 0){printf("send err\n");close(sockfd);exit(1);}}void *pthread_fun(int *sock){int sockfd = *sock;char recvbuf[1024] = {0};int n = 0;char *p,*q;char name2[20] = {0};while(1){memset(recvbuf,0,1024);n = recv(sockfd,recvbuf,sizeof(recvbuf),0);if(n<=0){printf("recv failed\n");exit(1);}if(!strncmp(recvbuf,"NOTICE\r\n通讯通道开启\r\n\r\n",30)){ printf("通讯通道开启\n");FLAGE=1;if (!strncmp(recvbuf, "100\r\n", 5)) {char *p = strtok(recvbuf + 5, "\r\n\r\n");//100\r\n:3个字符后取出\r\n\r\n前的名字strcpy(name2, p);printf("[NOTICE]%s进入聊天室\n", name2);FLAGE = 4;}if (!strncmp(recvbuf, "ERROR\r\n用户名重复\r\n\r\n", 26)) {printf("用户名重复\n");FLAGE = 3;}if (!strncmp(recvbuf, "200\r\n", 5)) {p = strtok(recvbuf+5,"\r\n\r\n");while(p != NULL){printf("%s\n",p);p = strtok(NULL,"\r\n\r\n");}printf("please input con:\n");}if(!strncmp(recvbuf,"AFROM\r\n",7)){// printf("recvbuf=%s\n",recvbuf);p = strtok(recvbuf+6,"\r\n");q = strtok(NULL,"\r\n\r\n");printf("(%s)[群聊]:%s\n",p, q);printf("please input con:\n");}if(!strncmp(recvbuf,"FROM\r\n",6)){p = strtok(recvbuf+6,"\r\n");q = strtok(NULL,"\r\n\r\n");printf("(%s)[私聊](%s):%s\n",p,name,q);printf("please input con:\n");}if(!strncmp(recvbuf,"ERROR2\r\n",8)){p = strtok(recvbuf + 8, "\r\n");printf("%s\n", p);}if(!strncmp(recvbuf,"NOTICE1\r\n",9)){p = strtok(recvbuf + 9, "\r\n");printf("用户%s\n", p);}if(!strncmp(recvbuf,"NOTICE\r\n服务器已满,请等候\r\n\r\n",37)){printf("服务器已满,请等候\n");FLAGE = 0;if(!strncmp(recvbuf,"NOTICE\r\n您已被唤醒,请继续操作\r\n\r\n",45)){ printf("你已经被唤醒,请继续操作\n");FLAGE = 2;}}}int main(int argc,char **argv){if(argc != 2){printf("input server ip:\n");exit(1);}pthread_t pid;int sockfd;struct sockaddr_in addr;char recvbuf[1024] = {0};char sendbuf[1024] = {0};int k=0;int n;char str[6] = {0};char *p,*q;if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){perror("socket");exit(1);}bzero(&addr,sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(PORT);if(inet_pton(AF_INET,argv[1],(void *)&addr.sin_addr) <= 0){perror("inet_pton");exit(1);}// inet_aton(argv[1], &addr.sin_addr);if(connect(sockfd,(struct sockaddr *)&addr,sizeof(addr)) == -1){ perror("connect");exit(1);}printf("connect success\n");// pid = fork();pthread_create(&pid,NULL,(void *)pthread_fun,(void*)&sockfd);pthread_detach(pid);// if(pid > 0){usleep(100);//让子进程先运行while(FLAGE==0){printf("服务器已满,wait...\n");sleep(1);}tcflush(0,TCIFLUSH);while(FLAGE==2){ //当FLAGE=2时正好父进程运行,则等待,FLAGE=1 usleep(100);}if(FLAGE == 1){while(k<3){//fflush(stdin);memset(name,0,20);printf("login:");scanf("%s",name);//fflush(stdin);sprintf(sendbuf,"LOGIN\r\n%s\r\n\r\n",name);send(sockfd,sendbuf,strlen(sendbuf),0);memset(sendbuf,0,1024);for(;;){if(FLAGE==3 || FLAGE==4)break;}if(FLAGE==3){k++;if(k==3){printf("输入过多,退出\n");}else{printf("还有%d次机会登录\n", 3 - k);}FLAGE=1;continue;}if(FLAGE==4){while(1){memset(str,0,6);scanf("%s",str);if(!strcmp(str,"show")){printf("显示在线用户:\n");fun_show(sockfd);continue;}else if(!strcmp(str,"all")){printf("群聊模式");fun_all(sockfd);continue;}else if(!strcmp(str,"to")){printf("私聊模式");fun_one(sockfd);continue;}else if(!strcmp(str,"quit")){printf("退出聊天室\n");fun_quit(sockfd);close(sockfd);return;}else if(!strcmp(str,"help")){printf("all[聊天内容] 群聊\n");printf("to[name][聊天内容] 私聊\n");printf("quit 退出程序\n");printf("help 显示帮助信息\n");printf("please input con:\n");continue;}else{printf("请输入help查看指令:\n");continue;}}}}}// }wait(NULL);}。
C语言实现的聊天室功能随着互联网的普及,聊天室作为一种社交交流方式逐渐受到人们的重视和喜爱。
在计算机编程领域,C语言作为一种广泛应用的编程语言,也能够实现聊天室的功能。
本文将介绍如何用C语言来实现聊天室功能,并分析其实现原理和相关技术。
一、聊天室功能简介聊天室是一种通过计算机网络进行在线沟通交流的工具。
不同于即时通讯软件,聊天室可以容纳更多的用户同时进行交流,形成一个开放的群体。
用户在聊天室中可以发送消息、分享文件、进行语音/视频通话等操作,实现多种形式的交流和互动。
二、C语言实现聊天室的原理实现聊天室功能涉及到网络编程、进程间通信和多线程等技术。
下面是C语言实现聊天室功能的一般步骤:1. 创建服务器端和客户端程序;2. 服务器端程序启动时建立一个监听socket;3. 客户端程序启动时创建一个socket,并向服务器端发送连接请求;4. 服务器端收到请求后,接受连接请求,并创建一个新的线程来处理客户端的请求;5. 客户端和服务器端通过socket实现数据的发送和接收;6. 服务器端可采用多线程的方式实现对多个客户端的并发处理;7. 客户端和服务器端通过消息队列、共享内存或信号量等方式进行进程间通信;8. 聊天室程序运行结束后,关闭socket和释放相关资源。
三、C语言实现聊天室的技术考虑在实现聊天室功能时,需要考虑以下技术问题:1. 网络协议:聊天室可以基于TCP或UDP协议来实现,需要选择合适的协议来保证消息的可靠传输或实现实时性要求。
2. 进程通信:聊天室中的客户端和服务端需要进行进程间通信,可以选择合适的通信方式,如消息队列、共享内存、信号量等。
3. 多线程编程:服务器端需要支持多个客户端的并发连接,可以通过多线程来实现并发处理。
4. 用户注册登录:聊天室需提供用户注册和登录功能,可将用户信息存储在数据库中,并进行身份验证。
5. 数据库管理:聊天室需要管理用户、消息等数据,可以使用关系型数据库或其他形式的数据存储和管理。
Linux网络编程:用C语言实现的聊天程序(同步通信)通过TCP协议,用C语言实现的同步聊天程序,注释写的比较详细,个人觉得对字符串处理比较充分,能够正常编译运行,拿出来和大家分享一下!1、客户端源代码:[cpp]view plaincopyprint?1.#include <stdio.h>2.#include <stdlib.h>3.#include <string.h>4.#include <errno.h>5.#include <sys/socket.h>6.#include <arpa/inet.h>7.#include <netinet/in.h>8.#include <sys/types.h>9.#include <unistd.h>10.11.#define BUFLEN 1012.13.int main(int argc, char **argv)14.{15.int sockfd;16. struct sockaddr_in s_addr;17. socklen_t len;18. unsigned int port;19.char buf[BUFLEN];20.21. /*建立socket*/22. if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){23. perror("socket");24. exit(errno);25. }else26. printf("socket create success!\n");27.28. /*设置服务器端口*/29. if(argv[2])30. port = atoi(argv[2]);31. else32. port = 4567;33. /*设置服务器ip*/34. bzero(&s_addr, sizeof(s_addr));35. s_addr.sin_family = AF_INET;36. s_addr.sin_port = htons(port);37. if (inet_aton(argv[1], (struct in_addr *)&s_addr.sin_addr.s_addr) == 0) {38. perror(argv[1]);39. exit(errno);40. }41. /*开始连接服务器*/42. if(connect(sockfd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr)) == -1){43. perror("connect");44. exit(errno);45. }else46. printf("conncet success!\n");47.48. while(1){49. /******接收消息*******/50. bzero(buf,BUFLEN);51. len = recv(sockfd,buf,BUFLEN,0);52. if(len > 0)53. printf("服务器发来的消息是:%s,共有字节数是: %d\n",buf,len);54. else{55. if(len < 0 )56. printf("接受消息失败!\n");57. else58. printf("服务器退出了,聊天终止!\n");59. break;60. }61. _retry:62. /******发送消息*******/63. bzero(buf,BUFLEN);64. printf("请输入发送给对方的消息:");65. /*fgets函数:从流中读取BUFLEN-1个字符*/66. fgets(buf,BUFLEN,stdin);67. /*打印发送的消息*/68. //fputs(buf,stdout);69. if(!strncasecmp(buf,"quit",4)){70. printf("client 请求终止聊天!\n");71. break;72. }73. /*如果输入的字符串只有"\n",即回车,那么请重新输入*/74. if(!strncmp(buf,"\n",1)){75. printf("输入的字符只有回车,这个是不正确的\n");76. goto _retry;77. }78. /*如果buf中含有'\n',那么要用strlen(buf)-1,去掉'\n'*/79. if(strchr(buf,'\n'))80. len = send(sockfd,buf,strlen(buf)-1,0);81. /*如果buf中没有'\n',则用buf的真正长度strlen(buf)*/82. else83. len = send(sockfd,buf,strlen(buf),0);84. if(len > 0)85. printf("消息发送成功,本次共发送的字节数是:%d\n",len);86. else{87. printf("消息发送失败!\n");88. break;89. }90. }91. /*关闭连接*/92. close(sockfd);93.94. return 0;95.}2、服务器源代码:[cpp]view plaincopyprint?1.#include <stdio.h>2.#include <stdlib.h>3.#include <string.h>4.#include <errno.h>5.#include <sys/socket.h>6.#include <arpa/inet.h>7.#include <netinet/in.h>8.#include <sys/types.h>9.#include <unistd.h>10.11.#define BUFLEN 1012.13.int main(int argc, char **argv)14.{15.int sockfd, newfd;16. struct sockaddr_in s_addr, c_addr;17.char buf[BUFLEN];18. socklen_t len;19. unsigned int port, listnum;20.21. /*建立socket*/22. if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){23. perror("socket");24. exit(errno);25. }else26. printf("socket create success!\n");27. /*设置服务器端口*/28. if(argv[2])29. port = atoi(argv[2]);30. else31. port = 4567;32. /*设置侦听队列长度*/33. if(argv[3])34. listnum = atoi(argv[3]);35. else36. listnum = 3;37. /*设置服务器ip*/38. bzero(&s_addr, sizeof(s_addr));39. s_addr.sin_family = AF_INET;40. s_addr.sin_port = htons(port);41. if(argv[1])42. s_addr.sin_addr.s_addr = inet_addr(argv[1]);43. else44. s_addr.sin_addr.s_addr = INADDR_ANY;45. /*把地址和端口帮定到套接字上*/46. if((bind(sockfd, (struct sockaddr*) &s_addr,sizeof(struct sockaddr))) == -1){47. perror("bind");48. exit(errno);49. }else50. printf("bind success!\n");51. /*侦听本地端口*/52. if(listen(sockfd,listnum) == -1){53. perror("listen");54. exit(errno);55. }else56. printf("the server is listening!\n");57. while(1){58. printf("*****************聊天开始***************\n");59. len = sizeof(struct sockaddr);60. if((newfd = accept(sockfd,(struct sockaddr*) &c_addr, &len)) == -1){61. perror("accept");62. exit(errno);63. }else64. printf("正在与您聊天的客户端是:%s: %d\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port));65. while(1){66. _retry:67. /******发送消息*******/68. bzero(buf,BUFLEN);69. printf("请输入发送给对方的消息:");70. /*fgets函数:从流中读取BUFLEN-1个字符*/71. fgets(buf,BUFLEN,stdin);72. /*打印发送的消息*/73. //fputs(buf,stdout);74. if(!strncasecmp(buf,"quit",4)){75. printf("server 请求终止聊天!\n");76. break;77. }78. /*如果输入的字符串只有"\n",即回车,那么请重新输入*/79. if(!strncmp(buf,"\n",1)){80. printf("输入的字符只有回车,这个是不正确的\n");81. goto _retry;82. }83. /*如果buf中含有'\n',那么要用strlen(buf)-1,去掉'\n'*/84. if(strchr(buf,'\n'))85. len = send(newfd,buf,strlen(buf)-1,0);86. /*如果buf中没有'\n',则用buf的真正长度strlen(buf)*/87. else88. len = send(newfd,buf,strlen(buf),0);89. if(len > 0)90. printf("消息发送成功,本次共发送的字节数是:%d\n",len);91. else{92. printf("消息发送失败!\n");93. break;94. }95. /******接收消息*******/96. bzero(buf,BUFLEN);97. len = recv(newfd,buf,BUFLEN,0);98. if(len > 0)99. printf("客户端发来的信息是:%s,共有字节数是: %d\n",buf,len); 100. else{101. if(len < 0 )102. printf("接受消息失败!\n");103. else104. printf("客户端退出了,聊天终止!\n");105. break;106. }107. }108. /*关闭聊天的套接字*/109. close(newfd);110. /*是否退出服务器*/111. printf("服务器是否退出程序:y->是;n->否? ");112. bzero(buf, BUFLEN);113. fgets(buf,BUFLEN, stdin);114. if(!strncasecmp(buf,"y",1)){115. printf("server 退出!\n");116. break;117. }118. }119. /*关闭服务器的套接字*/120. close(sockfd);121. return 0;122.}3、编译源代码:new@new-desktop:~/linux/c$ gcc -Wall sync-client.c -o sync-clientnew@new-desktop:~/linux/c$ gcc -Wall sync-server.c -o sync-server4、运行服务器程序:new@new-desktop:~/linux/c$ ./sync-server 127.0.0.1 4567socket create success!bind success!the server is listening!*****************聊天开始***************正在与您聊天的客户端是:127.0.0.1: 48639请输入发送给对方的消息:client消息发送成功,本次共发送的字节数是:6客户端发来的信息是:server,共有字节数是: 6请输入发送给对方的消息:5、运行客户端程序:new@new-desktop:~/linux/c$ ./sync-client 127.0.0.1 4567socket create success!conncet success!服务器发来的消息是:client,共有字节数是: 6请输入发送给对方的消息:server消息发送成功,本次共发送的字节数是:6linux网络编程:用C语言实现的聊天程序(异步通信)本片文章,在上一篇:linux网络编程:用C语言实现的聊天程序(同步通信)的基础上,增加了IO复用的功能,实现了聊天程序的异步通讯!1、使用IO复用可以在等待的时候加入了超时的时间,如果等待的时间没有达到超时时间,那么该情况与阻塞的情况一致。
c语言线程间的通信
在C语言中,线程间的通信可以通过多种方式实现,包括以下几种常用方法:
1. 共享内存:通过在多个线程之间共享一块内存区域来进行数据通信。
可以使用标准库中的`shmget()`函数创建共享内存,然后使用`mmap()`函数将共享内存映射到各个线程的地址空间。
2. 信号量:通过信号量控制多个线程的访问权限,从而实现线程间的同步和互斥。
可以使用`sem_init()`函数初始化一个信号量,然后使用`sem_wait()`和`sem_post()`函数进行等待和释放操作。
3. 互斥锁:通过互斥锁保护共享资源的访问,从而实现线程间的互斥访问。
可以使用`pthread_mutex_init()`函数初始化一个互斥锁,然后使用`pthread_mutex_lock()`和`pthread_mutex_unlock()`函数对互斥锁进行加锁和解锁操作。
4. 条件变量:通过条件变量实现线程间的等待和唤醒操作,从而实现线程间的同步。
可以使用`pthread_cond_init()`函数初始化一个条件变量,然后使用`pthread_cond_wait()`和
`pthread_cond_signal()`函数进行等待和唤醒操作。
5. 管道:通过管道在多个线程之间传输数据。
可以使用
`pipe()`函数创建一个管道,然后使用`read()`和`write()`函数进行读写操作。
以上是常见的几种线程间通信的方法,具体选择哪种方法取决于具体的需求和场景。
用 C 实现多线程 Socket 的通信Socket 是一种基于 IP 协议的网络协议,它提供网络连接和数据传输服务。
在多线程编程中,可以使用 Socket 实现线程之间的通信。
本文将介绍如何用 C 语言实现多线程 Socket 的通信。
首先,需要引入以下头文件:```#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <pthread.h>```其中,pthread.h 提供了用于多线程编程的函数和数据类型。
下面是一个简单的 Server 实现代码:```cvoid *server_thread(void *arg) {int server_fd, new_socket;struct sockaddr_in address;int opt = 1;int addrlen = sizeof(address);char buffer[1024] = {0};char *message = "Hello from server";int port = *(int*)arg;// 创建 Socketif ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("Socket failed");exit(EXIT_FAILURE);}// 设置 Socket 选项if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {perror("setsockopt");exit(EXIT_FAILURE);}address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(port);// 绑定 Socket 到端口号if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}// 监听来自客户端的连接请求if (listen(server_fd, 3) < 0) {perror("listen");exit(EXIT_FAILURE);}// 接受客户端连接if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");exit(EXIT_FAILURE);}// 发送消息给客户端send(new_socket, message, strlen(message), 0);printf("Message sent to client\n");// 接收来自客户端的消息read(new_socket, buffer, 1024);printf("Message from client: %s\n", buffer);close(new_socket);close(server_fd);return NULL;}```上述代码中,server_thread 函数是一个 pthread_create 函数即可创建一个新的线程执行该函数:```cint main() {int port = 8080;pthread_t t_id;if (pthread_create(&t_id, NULL, server_thread, &port) != 0) { perror("pthread_create failed");exit(EXIT_FAILURE);}// 等待子线程结束pthread_join(t_id, NULL);return 0;}```当客户端连接到 Server 后,Server 发送一条消息给客户端,然后等待客户端发送消息过来。
Linux网络编程:用C语言实现的聊天程序(同步通信)通过TCP协议,用C语言实现的同步聊天程序,注释写的比较详细,个人觉得对字符串处理比较充分,能够正常编译运行,拿出来和大家分享一下!1、客户端源代码:[cpp]view plainc opyprint?1.#includ e <stdio.h>2.#includ e <stdlib.h>3.#includ e <string.h>4.#includ e <errno.h>5.#includ e <sys/socket.h>6.#includ e <arpa/inet.h>7.#includ e <netine t/in.h>8.#includ e <sys/types.h>9.#includ e <unistd.h>10.11.#define BUFLEN 1012.13.int main(int argc, char **argv)14.{15.int sockfd;16. struct sockad dr_in s_addr;17. sockle n_t len;18. unsign ed int port;19.char buf[BUFLEN];20.21. /*建立sock et*/22. if((sockfd = socket(AF_INE T, SOCK_S TREAM, 0)) == -1){23. perror("socket");24. exit(errno);25. }else26. printf("socket create succes s!\n");27.28. /*设置服务器端口*/29. if(argv[2])30. port = atoi(argv[2]);31. else32. port = 4567;33. /*设置服务器i p*/34. bzero(&s_addr, sizeof(s_addr));35. s_addr.sin_fa mily= AF_INE T;36. s_addr.sin_po rt = htons(port);37. if (inet_a ton(argv[1], (struct in_add r *)&s_addr.sin_ad dr.s_addr) == 0) {38. perror(argv[1]);39. exit(errno);40. }41. /*开始连接服务器*/42. if(connec t(sockfd,(struct sockad dr*)&s_addr,sizeof(struct sockad dr)) == -1){43. perror("connec t");44. exit(errno);45. }else46. printf("connce t succes s!\n");47.48. while(1){49. /******接收消息*******/50. bzero(buf,BUFLEN);51. len = recv(sockfd,buf,BUFLEN,0);52. if(len > 0)53. printf("服务器发来的消息是:%s,共有字节数是: %d\n",buf,len);54. else{55. if(len < 0 )56. printf("接受消息失败!\n");57. else58. printf("服务器退出了,聊天终止!\n");59. break;60. }61. _retry:62. /******发送消息*******/63. bzero(buf,BUFLEN);64. printf("请输入发送给对方的消息:");65. /*fgets函数:从流中读取B UFLEN-1个字符*/66. fgets(buf,BUFLEN,stdin);67. /*打印发送的消息*/68. //fputs(buf,stdout);69. if(!strnca secmp(buf,"quit",4)){70. printf("client请求终止聊天!\n");71. break;72. }73. /*如果输入的字符串只有"\n",即回车,那么请重新输入*/74. if(!strncm p(buf,"\n",1)){75. printf("输入的字符只有回车,这个是不正确的!!!\n");76. goto _retry;77. }78. /*如果buf中含有'\n',那么要用st rlen(buf)-1,去掉'\n'*/79. if(strchr(buf,'\n'))80. len = send(sockfd,buf,strlen(buf)-1,0);81. /*如果buf中没有'\n',则用buf的真正长度s trlen(buf)*/82. else83. len = send(sockfd,buf,strlen(buf),0);84. if(len > 0)85. printf("消息发送成功,本次共发送的字节数是:%d\n",len);86. else{87. printf("消息发送失败!\n");88. break;89. }90. }91. /*关闭连接*/92. close(sockfd);93.94. return 0;95.}2、服务器源代码:[cpp]view plainc opyprint?1.#includ e <stdio.h>2.#includ e <stdlib.h>3.#includ e <string.h>4.#includ e <errno.h>5.#includ e <sys/socket.h>6.#includ e <arpa/inet.h>7.#includ e <netine t/in.h>8.#includ e <sys/types.h>9.#includ e <unistd.h>10.11.#define BUFLEN 1012.13.int main(int argc, char **argv)14.{15.int sockfd, newfd;16. struct sockad dr_in s_addr, c_addr;17.char buf[BUFLEN];18. sockle n_t len;19. unsign ed int port, listnu m;20.21. /*建立sock et*/22. if((sockfd = socket(AF_INE T, SOCK_S TREAM, 0)) == -1){23. perror("socket");24. exit(errno);25. }else26. printf("socket create succes s!\n");27. /*设置服务器端口*/28. if(argv[2])29. port = atoi(argv[2]);30. else31. port = 4567;32. /*设置侦听队列长度*/33. if(argv[3])34. listnu m = atoi(argv[3]);35. else36. listnu m = 3;37. /*设置服务器i p*/38. bzero(&s_addr, sizeof(s_addr));39. s_addr.sin_fa mily= AF_INE T;40. s_addr.sin_po rt = htons(port);41. if(argv[1])42. s_addr.sin_ad dr.s_addr = inet_a ddr(argv[1]);43. else44. s_addr.sin_ad dr.s_addr = INADDR_ANY;45. /*把地址和端口帮定到套接字上*/46. if((bind(sockfd, (struct sockad dr*) &s_addr,sizeof(struct sockad dr))) == -1){47. perror("bind");48. exit(errno);49. }else50. printf("bind succes s!\n");51. /*侦听本地端口*/52. if(listen(sockfd,listnu m) == -1){53. perror("listen");54. exit(errno);55. }else56. printf("the server is listen ing!\n");57. while(1){58. printf("*****************聊天开始***************\n");59. len = sizeof(struct sockad dr);60. if((newfd= accept(sockfd,(struct sockad dr*) &c_addr, &len)) == -1){61. perror("accept");62. exit(errno);63. }else64. printf("正在与您聊天的客户端是:%s: %d\n",inet_n toa(c_addr.sin_ad dr),ntohs(c_addr.sin_po rt));65. while(1){66. _retry:67. /******发送消息*******/68. bzero(buf,BUFLEN);69. printf("请输入发送给对方的消息:");70. /*fgets函数:从流中读取B UFLEN-1个字符*/71. fgets(buf,BUFLEN,stdin);72. /*打印发送的消息*/73. //fputs(buf,stdout);74. if(!strnca secmp(buf,"quit",4)){75. printf("server请求终止聊天!\n");76. break;77. }78. /*如果输入的字符串只有"\n",即回车,那么请重新输入*/79. if(!strncm p(buf,"\n",1)){80. printf("输入的字符只有回车,这个是不正确的!!!\n");81. goto _retry;82. }83. /*如果buf中含有'\n',那么要用st rlen(buf)-1,去掉'\n'*/84. if(strchr(buf,'\n'))85. len = send(newfd,buf,strlen(buf)-1,0);86. /*如果buf中没有'\n',则用buf的真正长度s trlen(buf)*/87. else88. len = send(newfd,buf,strlen(buf),0);89. if(len > 0)90. printf("消息发送成功,本次共发送的字节数是:%d\n",len);91. else{92. printf("消息发送失败!\n");93. break;94. }95. /******接收消息*******/96. bzero(buf,BUFLEN);97. len = recv(newfd,buf,BUFLEN,0);98. if(len > 0)99. printf("客户端发来的信息是:%s,共有字节数是: %d\n",buf,len); 100. else{101. if(len < 0 )102. printf("接受消息失败!\n");103. else104. printf("客户端退出了,聊天终止!\n");105. break;106. }107. }108. /*关闭聊天的套接字*/109. close(newfd);110. /*是否退出服务器*/111. printf("服务器是否退出程序:y->是;n->否? ");112. bzero(buf, BUFLEN);113. fgets(buf,BUFLEN, stdin);114. if(!strnca secmp(buf,"y",1)){115. printf("server退出!\n");116. break;117. }118. }119. /*关闭服务器的套接字*/120. close(sockfd);121. return 0;122.}3、编译源代码:new@new-deskto p:~/linux/c$ gcc -Wall sync-client.c -o sync-clientnew@new-deskto p:~/linux/c$ gcc -Wall sync-server.c -o sync-server4、运行服务器程序:new@new-deskto p:~/linux/c$ ./sync-server 127.0.0.1 4567socket create succes s!bind success!the server is listening!*****************聊天开始***************正在与您聊天的客户端是:127.0.0.1: 48639请输入发送给对方的消息:client消息发送成功,本次共发送的字节数是:6客户端发来的信息是:server,共有字节数是: 6请输入发送给对方的消息:5、运行客户端程序:new@new-deskto p:~/linux/c$ ./sync-client 127.0.0.1 4567socket create succes s!connce t succes s!服务器发来的消息是:client,共有字节数是: 6请输入发送给对方的消息:server消息发送成功,本次共发送的字节数是:6linux网络编程:用C语言实现的聊天程序(异步通信)本片文章,在上一篇:linux网络编程:用C语言实现的聊天程序(同步通信)的基础上,增加了IO复用的功能,实现了聊天程序的异步通讯!1、使用IO复用可以在等待的时候加入了超时的时间,如果等待的时间没有达到超时时间,那么该情况与阻塞的情况一致。
C++实现简单的⽹络聊天程序1、什么是socket,socket在哪?Socket是应⽤层与 TCP/IP协议族通信的中间软件抽象层,它是⼀组接⼝。
在设计模式中,Socket其实就是⼀个门⾯模式,它把复杂的TCP/IP协议族隐藏在Socket接⼝后⾯,对⽤户来说,⼀组简单的接⼝就是全部,让Socket去组织数据,以符合指定的协议。
socket起源于Unix,⽽Unix/Linux基本哲学之⼀就是“⼀切皆⽂件”,都可以⽤“打开open –> 读写write/read –> 关闭close”模式来操作,Socket就是该模式的⼀个实现,socket即是⼀种特殊的⽂件,⼀些socket函数就是对其进⾏的操作(读/写、打开、关闭),这些函数我们在后⾯进⾏介绍。
有三种不同形式的套接字:流式套接字(SOCK_STREAM),数据包套接字(SOCK_DGRAM),原始套接字(SOCK_RAW)。
基于TCP的Socket使⽤流式套接字,相⽐于使⽤数据包套接字的UDP来讲,TCP可以使程序员不必关⼼数据正确性及顺序正确性,缺点是效率较低。
基于TCP的Socket编程最常见的应⽤场景是在C/S架构下的分布式应⽤,针对客户端和服务器端提供不同的Socket系统调⽤。
2、client/server(CS)模式服务端:服务器端: 初始化 socket套接字----->绑定socket----->对端⼝进⾏监听(listen)----->阻塞(accept)----->等待客户端连接,⾄此程序运⾏到刚启动服务端的状态。
客户端:初始化 socket套接字------>发送连接请求(connect),如果连接成功,客户端发送数据请求,服务器接受请求并处理请求,把回应数据发送给客户端,客户端读取数据,最后关闭连接,完成⼀次交互。
3、实现代码及相关API介绍//服务器#include<iostream>#include<winsock.h>#pragma comment(lib,"ws2_32.lib")using namespace std;void initialization();int main() {//定义长度变量int send_len = 0;int recv_len = 0;int len = 0;//定义发送缓冲区和接受缓冲区char send_buf[100];char recv_buf[100];//定义服务端套接字,接受请求套接字SOCKET s_server;SOCKET s_accept;//服务端地址客户端地址SOCKADDR_IN server_addr;SOCKADDR_IN accept_addr;initialization();//填充服务端信息server_addr.sin_family = AF_INET;server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);server_addr.sin_port = htons(1234);//创建套接字s_server = socket(AF_INET, SOCK_STREAM, 0);if (bind(s_server, (SOCKADDR*)& server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {cout << "套接字绑定失败!" << endl;WSACleanup();}else {cout << "套接字绑定成功!" << endl;}//设置套接字为监听状态if (listen(s_server, SOMAXCONN) < 0) {cout << "设置监听状态失败!" << endl;WSACleanup();}else {cout << "设置监听状态成功!" << endl;}cout << "服务端正在监听连接,请稍候...." << endl;//接受连接请求len = sizeof(SOCKADDR);s_accept = accept(s_server, (SOCKADDR*)& accept_addr, &len);if (s_accept == SOCKET_ERROR) {cout << "连接失败!" << endl;WSACleanup();return0;}cout << "连接建⽴,准备接受数据" << endl;//接收数据while (1) {recv_len = recv(s_accept, recv_buf, 100, 0);if (recv_len < 0) {cout << "接受失败!" << endl;break;}else {cout << "客户端信息:" << recv_buf << endl;}cout << "请输⼊回复信息:";cin >> send_buf;send_len = send(s_accept, send_buf, 100, 0);if (send_len < 0) {cout << "发送失败!" << endl;break;}}//关闭套接字closesocket(s_server);closesocket(s_accept);//释放DLL资源WSACleanup();return0;}void initialization() {//初始化套接字库WORD w_req = MAKEWORD(2, 2);//版本号WSADATA wsadata;int err;err = WSAStartup(w_req, &wsadata);if (err != 0) {cout << "初始化套接字库失败!" << endl;}else {cout << "初始化套接字库成功!" << endl;}//检测版本号if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {cout << "套接字库版本号不符!" << endl;WSACleanup();}else {cout << "套接字库版本正确!" << endl;}//填充服务端地址信息}//客户端#include<iostream>#include<winsock.h>#pragma comment(lib,"ws2_32.lib")using namespace std;void initialization();int main() {//定义长度变量int send_len = 0;int recv_len = 0;//定义发送缓冲区和接受缓冲区char send_buf[100];char recv_buf[100];//定义服务端套接字,接受请求套接字SOCKET s_server;//服务端地址客户端地址SOCKADDR_IN server_addr;initialization();//填充服务端信息server_addr.sin_family = AF_INET;server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");server_addr.sin_port = htons(1234);//创建套接字s_server = socket(AF_INET, SOCK_STREAM, 0);if (connect(s_server, (SOCKADDR*)& server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) { cout << "服务器连接失败!" << endl;WSACleanup();}else {cout << "服务器连接成功!" << endl;}//发送,接收数据while (1) {cout << "请输⼊发送信息:";cin >> send_buf;send_len = send(s_server, send_buf, 100, 0);if (send_len < 0) {cout << "发送失败!" << endl;break;}recv_len = recv(s_server, recv_buf, 100, 0);if (recv_len < 0) {cout << "接受失败!" << endl;break;}else {cout << "服务端信息:" << recv_buf << endl;}}//关闭套接字closesocket(s_server);//释放DLL资源WSACleanup();return0;}void initialization() {//初始化套接字库WORD w_req = MAKEWORD(2, 2);//版本号WSADATA wsadata;int err;err = WSAStartup(w_req, &wsadata);if (err != 0) {cout << "初始化套接字库失败!" << endl;}else {cout << "初始化套接字库成功!" << endl;}//检测版本号if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2){cout << "套接字库版本号不符!" << endl;WSACleanup();}else {cout << "套接字库版本正确!" << endl;}//填充服务端地址信息}linux下和c++中相关API介绍:1)socket()函数int socket(int domain, int type, int protocol);domain:即协议域,⼜称为协议族(family)。
Linux下c语⾔多线程编程引⾔ 线程(thread)技术早在60年代就被提出,但真正应⽤多线程到中去,是在80年代中期,solaris是这⽅⾯的佼佼者。
传统的Unix也⽀持线程的概念,但是在⼀个进程(process)中只允许有⼀个线程,这样多线程就意味着多进程。
现在,多 为什么有了进程的概念后,还要再引⼊线程呢?使⽤多线程到底有哪些好处?什么的系统应该选⽤多线程?我们⾸先必须回答这些问题。
使⽤多线程的理由之⼀是和进程相⽐,它是⼀种⾮常"节俭"的多任务操作⽅式。
我们知道,在Linux系统下,启动⼀个新的进程必须分配给它独⽴的地址空间,建⽴众多的数据表来维护它的代码段、堆栈段和数据段,这是⼀种"昂贵"的多任务⼯作⽅式。
⽽运⾏于⼀个进程中的多个线程,它们彼此之间使⽤相同的地址空间,共享⼤部分数据,启动⼀个线程所花费的空间远远⼩于启动⼀个进程所花费的空间,⽽且,线程间彼此切换所需的时间也远远⼩于进程间切换所需要的时间。
使⽤多线程的理由之⼆是线程间⽅便的机制。
对不同进程来说,它们具有独⽴的数据空间,要进⾏数据的传递只能通过通信的⽅式进⾏,这种⽅式不仅费时,⽽且很不⽅便。
线程则不然,由于同⼀进程下的线程之间共享数据空间,所以⼀个线程的数据可以直接为其它线程所⽤,这不仅快捷,⽽且⽅便。
当然,数据的共享也带来其他⼀些问题,有的变量不能同时被两个线程所修改,有的⼦程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地⽅。
除了以上所说的优点外,不和进程⽐较,多线程程序作为⼀种多任务、并发的⼯作⽅式,当然有以下的优点: 1) 提⾼应⽤程序响应。
这对图形界⾯的程序尤其有意义,当⼀个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应、、菜单的操作,⽽使⽤多线程技术,将耗时长的操作(time consuming)置于⼀个新的线程,可以避免这种尴尬的情况。
c语言线程间通信的几种方法C语言是一种广泛应用于系统开发和嵌入式设备的编程语言,线程间通信是多线程编程中非常重要的一个概念。
线程间通信是指多个线程之间通过共享的资源或特定的机制来进行信息交流和同步操作的过程。
在C语言中,有多种方法可以实现线程间通信,下面将介绍几种常见的方法。
1. 互斥锁(Mutex)互斥锁是一种最常用的线程同步机制,用于保护共享资源的访问。
它通过在关键代码段前后加锁和解锁操作,使得同一时间只有一个线程可以访问共享资源,其他线程则需要等待。
互斥锁可以使用pthread库中的pthread_mutex_init、pthread_mutex_lock和pthread_mutex_unlock等函数来实现。
2. 条件变量(Condition Variable)条件变量是一种线程间通信的机制,用于在某个条件满足时唤醒等待的线程。
当某个线程发现自己需要等待某个条件时,它可以使用pthread库中的pthread_cond_wait函数来阻塞自己,并释放互斥锁,当其他线程满足了条件后,可以使用pthread_cond_signal函数来唤醒等待的线程。
3. 信号量(Semaphore)信号量是一种用于控制多个线程对共享资源访问的机制。
它通过一个计数器来表示可用的资源数量,当资源数量不足时,线程需要等待,而当资源数量充足时,线程可以继续执行。
信号量可以使用pthread库中的sem_init、sem_wait和sem_post等函数来实现。
4. 管道(Pipe)管道是一种允许两个线程进行双向通信的机制。
在C语言中,可以使用pipe函数来创建一个管道,并使用read和write函数来进行读取和写入操作。
一个线程可以利用管道将数据发送给另一个线程,并且可以实现双向通信。
5. 共享内存(Shared Memory)共享内存是一种允许多个线程访问同一块内存区域的机制。
多个线程可以通过共享内存来进行数据交换和通信。
多线程程序c语言多线程是计算机中的一个概念,它可以让多个线程同步运行,从而加快计算机运行速度,改善性能。
而在C语言中,使用多线程的方法也是被广泛应用于各个领域中的。
本文将为大家详细讲解如何在C语言中创建和管理多线程。
一、线程和进程的概念在C语言中,线程是执行代码的一种方式,它可以用来实现并发和异步编程。
而进程是资源分配的最小单位,每个进程都有自己的地址空间和独立的工作流程。
一个进程可以包含多个线程。
在操作系统的层面,每个线程都是由进程来管理的,由于线程共享进程的地址空间,所以它们之间的数据传递和通信比较方便。
二、多线程的实现方法在C语言中,要实现多线程的功能,需要使用相关的函数库。
其中最常用的函数库是pthread,使用它可以轻松地创建和管理多个线程。
1. 线程的创建线程的创建主要是通过pthread_create函数实现的。
它的原型定义如下:```#include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine)(void*), void *arg);```该函数的第一个参数是一个指向线程ID的指针,第二个参数是指向线程属性的指针,第三个参数是线程所要执行的函数,最后一个参数是传递给函数的参数。
调用成功后,会返回0,并将线程ID放到第一个参数所指向的地址中。
```#include <pthread.h>int pthread_cancel(pthread_t thread);```该函数的参数是要撤销的线程ID。
调用成功后,函数会直接将指定的线程终止掉,并释放它所占用的资源。
三、多线程的应用场景在C语言中,多线程的应用场景非常广泛,下面分别介绍几种典型的应用场景:1. 网络编程在网络编程中,要同时处理多个客户端请求,这时使用多线程可以使程序并发执行,效率更高。
基于TCP协议的简易网络聊天程序一、设计原理:即时通信(IM)是指能够即时发送和接收互联网消息等的业务。
自1998年面世以来,特别是近几年的迅速发展,即时通信的功能日益丰富,逐渐集成了电子邮件、博客、音乐、电视、游戏和搜索等多种功能。
即时通信不再是一个单纯的聊天工具,它已经发展成集交流、资讯、娱乐、搜索、电子商务、办公协作和企业客户服务等为一体的综合化信息平台。
本课题实现简单的及时通讯中的聊天服务。
问题定义:本课题要解决的问题是提供用户自由向另外一个不同的用户发消息的同时接收来自其他用户的消息。
2. 可行性研究:要实现即时通讯的聊天模块,可以在LINUX下搭建服务器,在提供给用户客户端程序。
客户端和服务器之间通过TCP协议实现在线聊天。
需求分析:(1)为了实现即时通讯的聊天服务,聊天服务器必须能够同时接入多个用户,所以要支持并发,允许同时在线客户端数量至少大于3个。
(2)要求服务器能接收多个用户的接入请求同时处理已经建立连接的用户的操作。
(3)接收用户发过来的信息。
(3)正确转发信息到达正确的用户。
(4)提供简单的用户操作指令比如显示实时在线的用户。
(5).来自不同用户的信息的转发的同步控制(6)。
给每个用户一个唯一的ID。
4. 总体设计首先我们应该在设计LINUX平台设计服务器并且C语言编程。
在实现并行处理时可以使用多进程也可以使用多线程,多线程可以方便的实现不同连接间简易的通信,系统开销小所以这里选用它。
在连接的协议选择上,因为传送数据量小,这里选择面向连接可靠传输的TCP协议,相比将套接字嵌入FILE留种,这里使用调用常用的tcp 的套接字API(send,recv)读写缓冲区实现连接的方法.5.详细设计客户端:首先用户提供服务器IP和端口,然后创建套接字并连接到服务器,连接成功给予操作界面。
设计用户登陆接口函数,发送名字用于登陆处理。
主进程挂载随时接收用户键盘输入,并调用SEND()函数处理发送和指令操作。
概述AbstractLinux作为免费开源操作系统广泛应用于企业。
Linux与UNIX有着深厚的渊源,而UNIX 系统可谓“坚如磐石”,其稳定性受到广泛赞誉。
近年来,越来越多的就业岗位被提供给了Linux 开发人员。
IM即时通讯软件是近年来流行的通信方式,企业、个人等都在更多地使用IM进行沟通。
通过计算机网络,信息的传递变得十分方便。
并非所有IM软件都要想腾讯QQ那样复杂、庞大,作为内部沟通,只需功能齐全、操作方便即可。
作为课程设计作品,在Linux下开发C/S式IM软件,对于熟悉Linux、复习计算机网络、进一步学习软件开发都有十分积极的意义。
As is open source software, Linux has been widely used in corporations. These years, more and more jobs are offered to Linux developers, for Linux spoken highly of for its stability as UNIX.IM software has become the most widely used communication software both for business use and for personal use. Through internetworks - including the Internet, Enterprise LAN, VPNs - information can be exchanged more conveniently and immediately. However, not all IM of C/S model is that complex as Tencent QQ. IM software inside an Enterprise LAN should be lighter and easier.As a product design of Linux, developing an IM software is helpful to reviewing key points of Linux, Internet, and software developing.目录1.1. 设计任务概述1.1.1.课题名称Linux下的IM网络聊天软件1.1.2.内容摘要随着嵌入式在生活中的应用越来越广泛,嵌入式LINUX下的Socket网络编程也越来越热。
C语⾔linux环境基于socket的简易即时通信程序最近在看linux⽹络编程相关,现学现卖,就写了⼀个简易的C/S即时通信程序,代码如下:head.h1/*头⽂件,client和server编译时都需要使⽤*/2 #include <unistd.h>3 #include <stdio.h>4 #include <sys/types.h>5 #include <sys/socket.h>6 #include <string.h>7 #include <pthread.h>8 #include <stdlib.h>9 #include <netinet/in.h>10 #include <arpa/inet.h>1112#define MSGLEN 100013#define IPLEN 151415 typedef int SOCKET;server.c:1/*server*/23 #include "head.h"45char msg_recv[MSGLEN], msg_send[MSGLEN];6 SOCKET server_sockfd, client_sockfd;78void *thread_function(void *argv) /*线程函数*/9 {10while(1){11 gets(msg_send);12 write(client_sockfd, msg_send, MSGLEN);13 }14 pthread_exit(NULL);15 }1617int main(int arg, char *argv[])18 {19int server_len, client_len;20struct sockaddr_in server_address;21struct sockaddr_in client_address;22int port;23int res;2425 pthread_t a_thread;26void *thread_result;2728if (arg != 2){29 printf("server --portnum\n");30 exit(EXIT_FAILURE);31 }3233 sscanf(argv[1], "%d", &port); /*读⼊端⼝*/3435 server_sockfd = socket(AF_INET, SOCK_STREAM, 0);36 server_address.sin_family = AF_INET;37 server_address.sin_addr.s_addr = inet_addr("127.0.0.1");38 server_address.sin_port = htons(port);3940 server_len = sizeof(server_address);41 bind(server_sockfd, (struct sockaddr *)&server_address, server_len); /*绑定端⼝并监听*/42 listen(server_sockfd, 10);43 printf("listen...\n");4445 client_len = sizeof(client_address);46 client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len);47 printf("connection success!\n");4849 res = pthread_create(&a_thread, NULL, thread_function, NULL); /*启动线程函数*/50if (res != 0){51 perror("Thread creation failed");52 exit(EXIT_FAILURE);53 }5455while(read(client_sockfd, msg_recv, MSGLEN)){56 printf("msg from client: %s\n", msg_recv);57 }58 close(client_sockfd);59 exit(EXIT_SUCCESS);60 }client.c:1/*client*/23 #include "head.h"45char msg_recv[MSGLEN],msg_send[MSGLEN];6 SOCKET sockfd;78void *thread_function(void *argv) /*线程函数*/9 {10while(1){11 gets(msg_send);12 write(sockfd, msg_send, MSGLEN);13 }14 pthread_exit(NULL);15 }1617int main(int arg, char *argv[])18 {19struct sockaddr_in address;20int len;21int res;22int port;23char ip[IPLEN];2425void *thread_result;26 pthread_t a_thread;2728 sockfd = socket(AF_INET, SOCK_STREAM, 0);2930if (arg != 3){31 printf("client --ipaddress --portnum\n");32 exit(EXIT_FAILURE);33 }3435 sscanf(argv[1], "%s", ip);36 sscanf(argv[2], "%d", &port); /*读取ip与端⼝*/3738 address.sin_family = AF_INET;39 address.sin_addr.s_addr = inet_addr(ip);40 address.sin_port = htons(port);4142 len = sizeof(address);43 res = connect(sockfd, (struct sockaddr *)&address, len);44if (res == -1){45 perror("connect failed! ");46 exit(EXIT_FAILURE);47 }48 printf("connection success!\n");4950 res = pthread_create(&a_thread, NULL, thread_function, NULL); /*启动线程函数*/ 51if (res != 0){52 perror("Thread creation failed");53 exit(EXIT_FAILURE);54 }5556while(read(sockfd, msg_recv, MSGLEN)){57 printf("msg from server: %s\n", msg_recv);58 }59 res = pthread_join(a_thread, &thread_result);60if (res != 0){61 perror("joined failed");62 exit(EXIT_FAILURE);63 }64 exit(EXIT_SUCCESS);65 }由于使⽤了线程,所以要链接正确的线程库,所以编译命令如下:gcc -D_REENTRANT -I/usr/include/nptl server.c -o server -L/usr/lib/nptl -lpthreadgcc -D_REENTRANT -I/usr/include/nptl client.c -o client -L/usr/lib/nptl -lpthread如果你的系统默认使⽤的就是NPTL线程库,那么编译时就⽆需加上-I和-L选项运⾏时输⼊的命令规则是:./server --portnum #即server后⾯要加上需要绑定的端⼝号。
C语⾔实现简易clientserver⽹络多⼈聊天⼯具⼀、C语⾔实现⼀个简易的client/server聊天⼯具 在ubuntu平台上,采⽤c语⾔实现⼀个简易的client/server聊天⼯具,思路是: 服务器端:⾸先创建⼀个服务器进程,该进程监听客户端的连接,如果收到并建⽴连接后创建⼀个线程服务该客户端。
该线程负责消息的转发(这⾥为了⽅便直接对消息进⾏⼴播)。
客户端:客户端进程⾸先创建⼀个线程⽤于消息接收处理,然后为⽤户提供信息输⼊的交互界⾯。
主要调⽤栈: int socket( int domain, int type, int protocol)功能:创建⼀个新的套接字,返回套接字描述符参数说明:domain:域类型,指明使⽤的协议栈,如TCP/IP使⽤的是 PF_INETtype: 指明需要的服务类型, 如SOCK_DGRAM: 数据报服务,UDP协议SOCK_STREAM: 流服务,TCP协议protocol:⼀般都取0举例:s=socket(PF_INET,SOCK_STREAM,0) int connect(int sockfd,struct sockaddr *server_addr,int sockaddr_len)功能:同远程服务器建⽴主动连接,成功时返回0,若连接失败返回-1。
参数说明:Sockfd:套接字描述符,指明创建连接的套接字Server_addr:指明远程端点:IP地址和端⼝号sockaddr_len :地址长度 int bind(int sockfd,struct sockaddr * my_addr,int addrlen)功能:为套接字指明⼀个本地端点地址TCP/IP协议使⽤sockaddr_in结构,包含IP地址和端⼝号,服务器使⽤它来指明熟知的端⼝号,然后等待连接参数说明:Sockfd:套接字描述符,指明创建连接的套接字my_addr:本地地址,IP地址和端⼝号addrlen :地址长度举例:bind(sockfd, (struct sockaddr *)&address, sizeof(address)); int listen(int sockfd,int input_queue_size)功能:⾯向连接的服务器使⽤它将⼀个套接字置为被动模式,并准备接收传⼊连接。
linux下c语⾔的多线程编程我们在写linux的服务的时候,经常会⽤到linux的多线程技术以提⾼程序性能多线程的⼀些⼩知识:⼀个应⽤程序可以启动若⼲个线程。
线程(Lightweight Process,LWP),是程序执⾏的最⼩单元。
⼀般⼀个最简单的程序最少会有⼀个线程,就是程序本⾝,也就是主函数(单线程的进程可以简单的认为只有⼀个线程的进程)⼀个线程阻塞并不会影响到另外⼀个线程。
多线程的进程可以尽可能的利⽤系统CPU资源。
1创建线程先上⼀段在⼀个进程中创建⼀个线程的简单的代码,然后慢慢深⼊。
#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include<string.h>#include<errno.h>void * func(void * arg){printf("func run...\n");return NULL;}int main(){pthread_t t1;int err = pthread_create(&t1,NULL,func,NULL);if(err!=0){printf("thread_create Failed:%s\n",strerror(errno));}else{printf("thread_create success\n");}sleep(1);return EXIT_SUCCESS;}int pthread_create(pthread_t *thread,const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);在main函数⾥⾯我们调⽤上⾯的函数进⾏创建⼀个线程。
函数参数: 第⼀个参数:pthread_t代表创建线程的唯⼀标识,是⼀个结构体,需要我们创建好后,将这个结构体的指针传递过去。
《Linux课程设计》Linux下聊天工具的设计与实现课题: Linux下网络聊天工具的设计与实现姓名:学号:班级: 2014级通信工程班指导教师:设计时间: 2017.06.30摘要这个毕业论文整体采用在linux平台下,在同一局域网内实现聊天功能。
整体框架主要分为服务端和客户端两个部分,设置好ip和端口号,在Linux下编译和调试两主大块程序,实现服务端和各个客户端的连接,然后以服务端作为中继转实现客户端之间的通信。
由于服务端只有一个,而客户端可以有任意多个,所以服务端采用了链表来管理多个客户端的信息,客户端的信息发送通过封装在结构体中进行传输。
本设计采用TCP/IP协议保证连接可靠,并在项目管理中采用linux流行的gcc和makefile编译,提高了编译和调试效率,加快了项目的完成速度。
由于要模拟多个客户端,所以在运行的环境中需要在PC机上再克隆一个虚拟系统来操作多个客户端。
本次设计的聊天工具采用字符串命令行的方式进行通信,主要实现了五个功能:新用户的注册与登录,用户之间一对一的聊天,用户之间群聊,用户之间文件加密传输,用户之间聊天记录保存。
经过测试,程序运行可靠,能满足在linux 中实现网络聊天的要求。
关键词linux,socket,gedit,服务端,客户端,网络编程ABSTRACTThis thesis gets the realization of chat in the same LAN under the Linux platform. The overall framework is divided into two parts: server and client. Set up the IP and port number, compile and debug two main bulk programs in the Linux and realize the connection between the server and the clients, and then realize the communication between clients by relying on server. Since there is only a server, but are multiple clients, so the server adopts a linked list to manage multiple clients’ information, and the information of clients is packed into struct to transfer. This design adopts the TCP/IP protocol to ensure reliable connection, and uses the Linux gcc and makefile compiler in project management, which improves the compiling and debugging efficiency, and speeds up the project’ completion. Due to the simulation of multiple clients, so it needs to clone a virtual system in the PC machine to operate multiple clients in the running environment.The chat tool of the design works by using the method of character string command line, which mainly accomplishes five functions: new users’ registration and login, biunique chat between users, users’ group chat, file encryption and transmission between users, users’ chat record retention. After the test, the program is reliable, and can meet the requirements of network chat in Linux.Keywords Linux, socket, gedit, server, client, network programming目录摘要 (I)ABSTRACT (II)1 绪论 (1)1.1研究背景 (1)1.1.1 Linux的介绍 (1)1.1.2 linux的发展史 (2)1.1.3 socket介绍 (2)1.2 研究意义 (3)1.3 国内外研究现状 (3)2 需求分析 (5)2.1 功能需求 (5)2.2 性能需求 (5)2.3模块划分 (5)2.4 模块调用关系 (6)2.5 系统总流程图 (6)2.6 文件信息安全 (8)3 linux网络编程 (9)3.1 socket概念及功能 (9)3.2 socket类型 (9)3.3 socket函数 (10)3.3.1 API功能介绍 (10)3.3.2 套接口地址结构 (10)3.3.3 基本转换函数 (13)3.3.4 socket编程流程 (13)3.4 TCP/IP协议 (14)3.4.1 OSI概述 (14)3.4.2 TCP/IP 协议概述 (15)3.4.3 TCP/IP层次结构 (17)3.4.4 TCP通信 (18)4 文件传输加密及相关技术 (20)4.1 文件描述符描述 (20)4.2 文件操作函数 (20)4.3 DES加密算法 (20)4.3.1 密钥计算过程 (21)4.3.2 初始置换ip和逆初始置换ip (21)4.3.3 P置换和扩充置换E (22)4.3.4 F函数和S盒置换 (22)4.4 linux线程通信 (23)4.5 链表 (24)5 具体实现 (25)5.1 登录和注册实现 (25)5.1.1 注册实现 (25)5.1.2 登录实现 (25)5.2 私聊和群聊 (26)5.2.1 私聊 (26)5.2.2 群聊 (26)5.3 文件传输和DES加密 (27)5.4 错误方案解决 (30)6 运行效果 (31)6.1 编译操作 (31)6.2 注册和登录运行效果图 (31)6.3 私聊和群聊效果图 (33)6.4 文件传输效果图 (34)6.5 文件内容加密效果图 (35)结束语 (36)参考文献 (37)致谢 (38)1 绪论随着Internet的快速发展和普及,网络已经遍布世界各个角落。
功能描述:程序应用多线程技术,可是实现1对N进行网络通信聊天。
但至今没想出合适的退出机制,除了用Ctr+C。
出于演示目的,这里采用UNIX域协议(文件系统套接字),程序分为客户端和服务端。
应用select函数来实现异步的读写操作。
先说一下服务端:首先先创建套接字,然后绑定,接下进入一个无限循环,用accept函数,接受“连接”请求,然后调用创建线程函数,创造新的线程,进入下一个循环。
这样每当有一个新的“连接”被接受都会创建一个新的线程,实现1对N的网络通信。
在服务端程序中线程中用一个buffer读写,为了避免错误,这时就要给关键代码加上互斥锁work_mutex,具体见代码。
服务端代码1#include<stdio.h>2#include<stdlib.h>3#include<string.h>4#include<pthread.h>5#include<sys/socket.h>6#include<sys/un.h>7#include<unistd.h>8#include<semaphore.h> //这里没有用二进制信号量可以删掉910char buffer[1024]; //读写用的区域11sem_t bin_sem; //没用到的二进制信号量,可以删掉12void *pthread_function(void *arg); //线程入口函数声明13pthread_mutex_t work_mutex; //声明互斥锁1415int main(){16int result; //整数变量用来储存调用函数的返回值17struct sockaddr_un server_address, client_address; //UNIX域的套接字,server_address用于服务端的监听,client_addr ess用于客户端连接后的套接字18int client_len; //连接后,accept函数会把客户端的地址的长度储存在这19int server_socketfd, client_socketfd;//服务端和客户端的套接字文件描述符20 pthread_t a_thread; //线程ID标志21 pthread_attr_t thread_attr; //线程的属性,后面可以看的,被我注释掉了,没用到,可以删掉。
2223 result = sem_init(&bin_sem, 0, 1); //初始化二进制信号量,因为用了互斥锁,所以没用到,可以删掉24if(result != 0){25 perror("sem_init");26 exit(EXIT_FAILURE);27 }2829 result = pthread_mutex_init(&work_mutex, NULL);//初始化互斥锁30if(result != 0){31 perror("pthread_mutex_init");32 exit(EXIT_FAILURE);33 }3435 server_socketfd = socket(AF_UNIX, SOCK_STREAM, 0);//创建套接字,用TCP连接方式,出于演示目的只用UNIX域套接字。
3637 server_address.sun_family = AF_UNIX;38 strcpy(server_address.sun_path, "server_socket"); 3940 unlink("server_socket"); //在绑定之前,把以前存在当前目录下的套接字删除4142 result = bind(server_socketfd, (struct sockaddr*)&server_address, sizeof(server_address)); //绑定43if(result != 0){44 perror("bind");45 exit(EXIT_FAILURE);46 }4748 result = listen(server_socketfd, 5);//监听,最多允许5个连接请求49if(result != 0){50 perror("listen");51 exit(EXIT_FAILURE);52 }5354 client_len = sizeof(client_address);55while(1){ //开始进入无限循环56/* printf("If you want to quit, please enter 'qui t'\n");57 printf("Do you want to accept a connectiong\n");58 memset(buffer, '\0', sizeof(buffer));59 fgets(buffer, sizeof(buffer), stdin);60 if((strncmp("quit", buffer, 4))==0) break; */6162 client_socketfd = accept(server_socketfd, (stru ct sockaddr*)&client_address, &client_len); //接受一个连接请求6364/* result = pthread_attr_init(&thread_attr);65 if(result != 0){66 perror("pthread_attr_init");67 exit(EXIT_FAILURE);68 }69 result = pthread_attr_setdetachstate(&thread_at tr, PTHREAD_CREATE_DETACHED);70 if(result != 0){71 perror("pthread_attr_setdetachstate");72 exit(EXIT_FAILURE);73 } */74 result = pthread_create(&a_thread, NULL, pthread _function, (void *)client_socketfd); //成功接受一个请求后,就会创建一个线程,然后主线程又进入accept函数,如果此时没有连接请求,那么主线程会阻塞75if(result != 0){76 perror("pthread_create");77 exit(EXIT_FAILURE);78 }7980 }81}8283void *pthread_function(void *arg){ //线程入口函数,每调用一次pthread_create,都会创建一个新的线程84int fd = (int) arg; //把函数参数,即连接成功后的套接字,赋给fd.85int result;86 fd_set read_fds; //文件描述符集合,用于select函数87int max_fds; //文件描述符集合的最大数8889 printf("%d id has connected!!\n", fd);90while (1){9192 FD_ZERO(&read_fds);//清空集合93 FD_SET(0, &read_fds);//将标准输入放入监听的文件描述符集合,这个用于读取标准输入,即键盘的输入94 FD_SET(fd, &read_fds);//将连接后的客户文件描述符放入监听的文件描述符集合,这个用于向客户端读取数据95 max_fds = fd + 1;9697// sem_wait(&bin_sem);98 pthread_mutex_lock(&work_mutex); //对关键区域上锁99 printf("%d has get the lock\n", fd);100 result = select(max_fds, &read_fds, (fd_set *)NU LL, (fd_set *)NULL, (struct timeval*)NULL); //开始监听那些文件描述符出于可读状态101if(result < 1){102 printf("select");103 }104if(FD_ISSET(0, &read_fds)){ //如果标准输入处于可读状态,说明键盘有所输入,将输入的数据存放在buffer中,然后向客户端写回,如果输入“quit”将会退出一个聊天线程105 memset(buffer, '\0', sizeof(buffer)); //保险起见,清零106 fgets(buffer, sizeof(buffer), stdin);107if((strncmp("quit", buffer, 4))==0){108 printf("You have terminaled the chat\n"); 109// sem_post(&bin_sem);110 pthread_mutex_unlock(&work_mutex);111break;112 }113else{114 result=write(fd, buffer, sizeof(buffer)); 115if(result==-1){116 perror("write");117 exit(EXIT_FAILURE);118 }119 }120 }121if(FD_ISSET(fd, &read_fds)){ //如果客户套接字符可读,那么读取存放在buffer中,然后显示出来,如果对方中断聊天,那么result==0122 memset(buffer, '\0', sizeof(buffer));123 result = read(fd, buffer, sizeof(buffer));124if(result == -1){125 perror("read");126 exit(EXIT_FAILURE);127 }128else if(result == 0){129 printf("The other side has terminal the c hat\n");130// sem_post(&bin_sem);131 pthread_mutex_unlock(&work_mutex);132break;133 }134else{135 printf("receive message: %s", buffer);136 }137 }138 pthread_mutex_unlock(&work_mutex); //解锁139 sleep (1); //如果没有这一行,当前线程会一直占据buffer.让当前线程暂停一秒可以实现1对N的功能。