tcp多人聊 天 室(支持断网重连)-udp实现聊天室

先上代码:

客户端: void thread1(void arg); void thread2(void arg); pthread_mutex_t lock; typedef struct sockaddr_in SAI; typedef struct sockaddr SA; SAI ser_addr; int socfd; char clientname[20]={0}; unsigned char rbuff[1024]={0}; char wbuff[1024]={0}; int main(int argc,char argv[]) { pthread_t tid1; pthread_t tid2; int connect_flag; int w_len; char buf[1024]={0}; pthread_mutex_init(&lock,NULL); //create socket file socfd=socket(AF_INET,SOCK_STREAM,0); bzero(&ser_addr,sizeof(ser_addr)); //configure serve address infomation ser_addr.sin_family = AF_INET; ser_addr.sin_port = htons(SERVER_PORT); ser_addr.sin_addr.s_addr = inet_addr(SERVER_IPADDR); //set username printf(“set username:”); scanf(“%s”,clientname); //connect to server if(connect(socfd,(SA)&ser_addr,sizeof(ser_addr))==-1) { printf(“connect fail\n”); return -1; } else{printf(“connect success\n”);} write(socfd,clientname,sizeof(clientname)); //bzero(clientname,sizeof(clientname)); //create a thread pthread_create(&tid1,NULL,thread1,NULL); pthread_create(&tid2,NULL,thread2,NULL); //send data while(1) { scanf(“%s”,wbuff); if(strncmp(wbuff,”quit”,4)==0) { close(socfd); exit(0); } w_len=write(socfd,wbuff,sizeof(wbuff)); if(w_len<0) { printf(“%s write fail”,clientname); } bzero(wbuff,sizeof(wbuff)); } close(socfd); } void thread1(void arg) { int r_len; int w_len; int tm=0; int flag=0; int jkl=0; while(1) { //r_len=read(socfd,rbuff,sizeof(rbuff)); r_len=recv(socfd,rbuff,sizeof(rbuff),MSG_DONTWAIT); if(r_len == 0) { //printf(“无数据\n”); //perror(“recv data”); //( “%s\n”, strerror( errno )); } if(r_len<0) { //perror(“recv data”); } if(rbuff[0]==0x86&&rbuff[1]==0x06&&rbuff[2]==0x00&&rbuff[3]==0x86&&rbuff[4]==0x01&&rbuff[5]==0x12) { w_len=write(socfd,”alive”,5); if(w_len<0) { printf(“write fail”); } goto AA; } if(strncmp(rbuff,”salive”,6)==0) { flag=0; goto AA; } else { flag++; if(flag>(10+3)) { printf(“网络断开超一次心跳,准备重连\n”); close(socfd); socfd=socket(AF_INET,SOCK_STREAM,0); jkl=connect(socfd,(SA*)&ser_addr,sizeof(ser_addr)); if(jkl==-1) { printf(“reconnect fail\n”); close(socfd); goto AA; } else { printf(“%s reconnect success\n”,clientname); write(socfd,clientname,sizeof(clientname)); write(socfd,”alive(reconnect)”,16); flag=0; goto AA; } } } if(strlen(rbuff)==0) { goto AA; } printf(“%s\n”,rbuff); AA://避免打印心跳包 bzero(rbuff,sizeof(rbuff)); sleep(1); } } void thread2(void arg) { int w_len; int jkl; int tm=0; char buf[1024]={0}; while(1) { //sleep(1); w_len=write(socfd,”testonline”,10); if(w_len<0) { printf(“write fail 188\n”); } bzero(buf,sizeof(buf)); sleep(10); } }
<

服务端:

void thread1(void arg); void thread2(void arg); void heartbeat(void arg); pthread_mutex_t lock; typedef struct sockaddr_in SAI; typedef struct sockaddr SA; SAI ser_addr,cli_addr; int socfd; int clifd_max = 0; int clifd_min = 4; pthread_t tid1[100]={0}; pthread_t tid2; pthread_t tid3; static int client_amount; int main(int argc,char* argv[]) { int r_len; int on = 1; int cliaddr_len; int clifd; cliaddr_len=sizeof(cli_addr); pthread_mutex_init(&lock,NULL); //create socket file socfd=socket(AF_INET,SOCK_STREAM,0); printf(“socfd:%d\n”,socfd); bzero(&ser_addr,sizeof(ser_addr)); bzero(&cli_addr,sizeof(cli_addr)); //configure serve address infomation ser_addr.sin_family = AF_INET; ser_addr.sin_port = htons(SERVER_PORT); ser_addr.sin_addr.s_addr = inet_addr(SERVER_IPADDR); setsockopt(socfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)); //bind address infomation with socket if(bind(socfd,(SA*)&ser_addr,sizeof(ser_addr))==-1) { printf(“bind fail\n”); return -1; } else{printf(“bind success\n”);} //set listen queue if(listen(socfd,LISTEN_Q_MAX)==-1) { printf(“set listen queue fail\n”); return -1; } else{printf(“set listen queue success\n”);} pthread_create(&tid2,NULL,thread2,(void*)clifd); pthread_create(&tid3,NULL,heartbeat,(void*)clifd); while(1) { //wait connecting clifd=accept(socfd,(SA*)&cli_addr,&cliaddr_len); pthread_mutex_lock(&lock); if(clifd > clifd_max) { clifd_max = clifd; } pthread_mutex_unlock(&lock); pthread_create(&tid1[client_amount],NULL,thread1,(void*)clifd); if(clifd==-1) { printf(“%d accept fail\n”,clifd); } else{printf(“%d (tid=%ld) accept success\n”,clifd,tid1[client_amount]);} client_amount++; printf(“已有%d个客户端连接上\n”,client_amount); } pthread_mutex_destroy(&lock); close(socfd); } void thread1(void arg) { int r_len; int clifd =(int)arg; char rbuff[1024]={0}; char wbuff[1024]={0}; char clientname[20]={0}; int flag=0; read(clifd,clientname,sizeof(clientname)); printf(“clifd:%d=%s\n”,clifd,clientname); while(1) { r_len=recv(clifd,rbuff,sizeof(rbuff),MSG_DONTWAIT); //r_len=read(clifd,rbuff,sizeof(rbuff));//MSG_DONTWAIT,MSG_WAITALL if(r_len == 0) { //printf(“无数据\n”); } if(r_len<0) { //perror(“recv data”); } if(strncmp(rbuff,”testonline”,10)==0) { printf(“recvfrom %s:tsetonline\n”,clientname); int w_len=write(clifd,”salive”,6); if(w_len<0) { printf(“write fail 122″); } goto BB; } if(strncmp(rbuff,”alive”,5)==0) { printf(“recvfrom %s:alive\n”,clientname); flag=0; goto BB; } else { flag++; if(flag>(10+1)) { printf(“网络断开超过一次心跳,关闭fd\n”); printf(“%s has disconnected\r\n”,clientname); client_amount—; printf(“还有%d个客户端连接着\n”,client_amount); close(clifd); pthread_exit(NULL); } } if(strlen(rbuff)==0) { goto BB; } printf(“recvfrom %s:%s\n”,clientname,rbuff); sprintf(wbuff,”%s:%s”,clientname,rbuff); pthread_mutex_lock(&lock); for(int j=clifd_min;j<=clifd_max;j++) { write(j,wbuff,sizeof(wbuff)); } pthread_mutex_unlock(&lock); BB: bzero(wbuff,sizeof(wbuff)); bzero(rbuff,sizeof(rbuff)); sleep(1); } } void thread2(void arg) { int w_len; int clifd =(int)arg; char buff[1024]={0}; char wbuff[1024]={0}; while(1) { scanf(“%s”,buff); if(strncmp(buff,”quit”,4)==0) { close(clifd); exit(0); } sprintf(wbuff,”server:%s”,buff); pthread_mutex_lock(&lock); for(int j=clifd_min;j<=clifd_max;j++) { write(j,wbuff,sizeof(wbuff)); } pthread_mutex_unlock(&lock); bzero(wbuff,sizeof(wbuff)); } } void heartbeat(void arg) { int w_len; int clifd =(int)arg; char buff[1024]={0}; char wbuff[1024]={0x86,0x06,0x00,0x86,0x01,0x12}; //int n=0; while(1) { pthread_mutex_lock(&lock); for(int j=clifd_min;j<=clifd_max;j++) { w_len=write(j,wbuff,sizeof(wbuff)); } pthread_mutex_unlock(&lock); sleep(10); } }
<

主要功能:各个客户端发送消息给服务器,然后服务器统一将这些消息发给其他客户端,从而达到聊 天 室的效果.支持断网重连.

断线重连:

服务器发送心跳包给客户端,如果失败,则提示断线,并且删除与客户端通信的会话

30秒发送一次心跳包。 发送数据段”0x86”给客户端,客户端接受后,返回“alive”,

同时客户端也会每30s向服务器发送”testonline”,服务器收到后会回复”salive”,如果没收到就会开始重连,知道连上为止.

中间主要有两个问题,一个是换成非阻塞接收数据后,返回值为0时有两个意思,一个是socket连接断开了,一个是对方发送空数据了,怎么处理这个空数据?我是默认返回值为0时不做处理,跳过buff内容为0的打印步骤,而确认断开连接我放在超时处理中了,这个虽然降低了实时性但基本能把这个问题处理掉.

第二个问题是断网重连后,用户名会丢失,这个主要是因为重连后的是新建了一个socket,然后再连上服务器的,在重连之前服务器把第一次接收到的数据作为用户名,所以就造成了用户名错乱的问题,解决方法是在新建socket之后将用户名发给服务器就好了.

以上都是我个人的理解,还有很多不到位的地方,希望各位大佬理解一下作为菜鸟的无奈L

免责声明:文章内容来自互联网,本站不对其真实性负责,也不承担任何法律责任,如有侵权等情况,请与本站联系删除。
转载请注明出处:tcp多人聊 天 室(支持断网重连)-udp实现聊天室 https://www.yhzz.com.cn/a/9730.html

上一篇 2023-04-20
下一篇 2023-04-20

相关推荐

联系云恒

在线留言: 我要留言
客服热线:400-600-0310
工作时间:周一至周六,08:30-17:30,节假日休息。