之前在学习关于网络tcp和多线程的编程,学了知识以后不用一下总绝对心虚,于是就编写了一个基于tcp和多线程的多人聊天室。
具体的实现过程:
服务器端:绑定socket对象->设置监听数->等待连接->有客户端连接就新建一个线程,这个线程中,一旦就收到这个客户发送的消息,就广播的向其他客户端发送同样的消息。
客户端:向客户端连接->新建线程用来接收服务器端发送的消息,同时主进程用来发送消息
话不多说,直接上代码
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10
11 typedef struct sockaddr *sockaddrp;12
13 //存储客户端地址的结构体数组
14 struct sockaddr_in src_addr[50];15 socklen_t src_len = sizeof(src_addr[0]);16
17
18
19 //连接后记录confd数组
20 int confd[50] ={};21
22
23 //设置连接人数
24 int count = 0;25
26
27 void *broadcast(void *indexp)28 {29 int index = *(int *)indexp;30 char buf_rcv[255] ={};31 char buf_snd[255] ={};32 //第一次读取用户姓名
33 char name[20] ={};34 int ret = recv(confd[index],name,sizeof(name),0);35 if(0 >ret)36 {37 perror("recv");38 close(confd[index]);39 return;40 }41
42 while(1)43 {44 bzero(buf_rcv,sizeof(buf_rcv));45 recv(confd[index],buf_rcv,sizeof(buf_rcv),0);46
47 //判断是否退出
48 if(0 == strcmp("quit",buf_rcv))49 {50 sprintf(buf_snd,"%s已经退出悟空聊天室",name);51 for(int i = 0;i <= count;i++)52 {53 if(i == index || 0 ==confd[i])54 {55 continue;56 }57
58 send(confd[i],buf_snd,strlen(buf_snd),0);59 }60 confd[index] = -1;61 pthread_exit(0);62
63 }64
65
66 sprintf(buf_snd,"%s:%s",name,buf_rcv);67 printf("%s\n",buf_snd);68 for(int i = 0;i <= count;i++)69 {70 if(i == index || 0 ==confd[i])71 {72 continue;73 }74
75 send(confd[i],buf_snd,sizeof(buf_snd),0);76 }77
78 }79
80 }81
82
83
84
85
86 int main(int argc,char **argv)87 {88 printf("悟空聊天室服务器端开始运行\n");89
90
91 //创建通信对象
92 int sockfd = socket(AF_INET,SOCK_STREAM,0);93 if(0 >sockfd)94 {95 perror("socket");96 return -1;97 }98
99 //准备地址
100 struct sockaddr_in addr ={AF_INET};101 addr.sin_port = htons(atoi(argv[1]));102 addr.sin_addr.s_addr = inet_addr(argv[2]);103
104 socklen_t addr_len = sizeof(addr);105
106
107
108 //绑定
109 int ret = bind(sockfd,(sockaddrp)&addr,addr_len);110 if(0 >ret)111 {112 perror("bind");113 return -1;114 }115
116
117 //设置最大排队数
118 listen(sockfd,50);119
120 int index = 0;121
122
123 while(count <= 50)124 {125 confd[count] = accept(sockfd,(sockaddrp)&src_addr[count],&src_len);126 ++count;127 //保存此次客户端地址所在下标方便后续传入
128 index = count-1;129
130 pthread_t tid;131 int ret = pthread_create(&tid,NULL,broadcast,&index);132 if(0 >ret)133 {134 perror("pthread_create");135 return -1;136 }137
138
139 }140
141
142 }
server.c
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8
9
10
11 typedef struct sockaddr *sockaddrp;12 intsockfd;13
14 void *recv_other(void *arg)15 {16 char buf[255]={};17 while(1)18 {19 int ret = recv(sockfd,buf,sizeof(buf),0);20 if(0 >ret)21 {22 perror("recv");23 return;24 }25 printf("%s\n",buf);26 }27 }28
29
30
31
32 int main(int argc,char **argv)33 {34 if(3 !=argc)35 {36 perror("参数错误");37 return -1;38 }39
40 //建立socket对象
41 sockfd = socket(AF_INET,SOCK_STREAM,0);42 if(0 >sockfd)43 {44 perror("socket");45 return -1;46 }47
48 //准备连接地址
49 struct sockaddr_in addr ={AF_INET};50 addr.sin_port = htons(atoi(argv[1]));51 addr.sin_addr.s_addr = inet_addr(argv[2]);52
53 socklen_t addr_len = sizeof(addr);54
55
56 //连接
57 int ret = connect(sockfd,(sockaddrp)&addr,addr_len);58 if(0 >ret)59 {60 perror("connect");61 return -1;62 }63
64 //发送名字
65 char buf[255] ={};66 char name[255] ={};67 printf("请输入您的昵称:");68 scanf("%s",name);69 ret = send(sockfd,name,strlen(name),0);70 if(0 >ret)71 {72 perror("connect");73 return -1;74 }75
76 //创建接收子线程
77 pthread_t tid;78 ret = pthread_create(&tid,NULL,recv_other,NULL);79
80 if(0 >ret)81 {82 perror("pthread_create");83 return -1;84 }85 //循环发送
86 while(1)87 {88 //printf("%s:",name);
89 scanf("%s",buf);90 int ret = send(sockfd,buf,strlen(buf),0);91 if(0 >ret)92 {93 perror("send");94 return -1;95 }96
97 //输入quit退出
98 if(0 == strcmp("quit",buf))99 {100 printf("%s,您已经退出了悟空聊天室\n",name);101 return 0;102 }103
104 }105
106 }
client.c
将两份代码分别编译生成相应可执行文件,例如在Linux下server,client,然后先执行./server 端口号 ip ,再执行./client 端口号 ip就可以运行这个聊天室了。
总结:关于网络编程,tcp是一种连接方式的通信方式,两边一旦建立连接,就可以通过send和recv函数发送消息,比较的可靠,缺点是速度比较慢(相对于udp来说)。另外关于多线程编程方面,线程其实是一个进程的实体,是一个进程的组成部分,多个线程共享除了栈区以外的大部分区域,因此进程间的通信比较方便,这种方便带来的代价是,当多个进程同时去操作同一量时,容易造成不可预知的错误,因此就引入了互斥量(锁)的概念,互斥量的使用就保证了进程间通信的同步。
原文:https://www.cnblogs.com/LyndonMario/p/9435684.html