Linux 即时聊天系统(tcp)epoll 版

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux 即时聊天系统(tcp)epoll 版相关的知识,希望对你有一定的参考价值。

简介:

  1.系统使用TCP来实现

  2.服务端 ctrl+d 能够使当前的客户端退出,但是服务端能够继续运行,并等待,响应其他的客户端的请求。ctrl+c 结束服务端进程

  3.ctrl+c 结束客户端进程

  4.服务器主要是用 epoll 模型实现,支持高并发

  <测试并可以正常运行>

  系统版本:Linux version 4.4.0-78-generic ([email protected]) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) )

 //头文件
1
#include <arpa/inet.h> 2 #include <sys/socket.h> 3 #include <netinet/in.h> 4 #include <stdio.h> 5 #include <netdb.h> 6 #include <string.h> 7 #include <sys/types.h> 8 #include <sys/socket.h> 9 #include <unistd.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <errno.h> 13 #include <sys/time.h> 14 #include <sys/epoll.h> 15 #include <signal.h>
  //服务端代码
1
#include"func.h" 2 3 int main(int argc,char *argv[]){ 4 //socket 5 int sfd = socket(AF_INET,SOCK_STREAM,0); 6 if(sfd == -1){ 7 perror("sfd"); 8 return -1; 9 } 10 //bind 11 struct sockaddr_in server; 12 memset(&server,0,sizeof(struct sockaddr_in)); 13 server.sin_family = AF_INET; 14 server.sin_port = htons(atoi(argv[2])); 15 server.sin_addr.s_addr = inet_addr(argv[1]); 16 int ret; 17 ret = bind(sfd,(struct sockaddr *)&server,sizeof(server)); 18 if(ret == -1){ 19 perror("bind"); 20 return -1; 21 } 22 //listen 23 ret = listen(sfd,10); 24 if(ret == -1){ 25 perror("listen"); 26 return -1; 27 } 28 29 printf("i am server\n"); 30 31 //epoll创建 32 int epfd = epoll_create(1); 33 34 struct epoll_event event,evs[3]; 35 //注册sfd 36 memset(&event,0,sizeof(event)); 37 event.events = EPOLLIN; 38 event.data.fd = sfd; 39 epoll_ctl(epfd,EPOLL_CTL_ADD,sfd,&event); 40 //注册0 41 memset(&event,0,sizeof(event)); 42 event.events = EPOLLIN; 43 event.data.fd = 0; 44 epoll_ctl(epfd,EPOLL_CTL_ADD,0,&event); 45 46 int ret1,i,len,new_fd; 47 char buf[128]={0}; 48 49 //新建client 50 struct sockaddr_in client; 51 while(1){ 52 memset(evs,0,sizeof(evs)); 53 int ret1 = epoll_wait(epfd,evs,3,-1); 54 if(ret1 > 0){ 55 for(i=0; i<ret1; i++){ 56 //sfd 有client请求建立里连接 57 if(evs[i].data.fd == sfd){ 58 memset(&client,0,sizeof(client)); 59 len = sizeof(client); 60 new_fd = accept(sfd,(struct sockaddr*)&client,&len); 61 if(new_fd == -1){ 62 perror("accept"); 63 return -1; 64 } 65 //注册new_fd 66 memset(&event,0,sizeof(event)); 67 event.events = EPOLLIN; 68 event.data.fd = new_fd; 69 epoll_ctl(epfd,EPOLL_CTL_ADD,new_fd,&event); 70 //打印客户端ip,端口 71 printf("client ip=%s,port=%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port)); 72 } 73 //0 服务端输入 74 if(evs[i].data.fd == 0){ 75 memset(buf,0,sizeof(buf)); 76 ret = read(0,buf,sizeof(buf)); 77 if(ret <= 0){ 78 printf("bye bye\n"); 79 close(new_fd); 80 //删除new_fd 81 memset(&event,0,sizeof(event)); 82 event.events = EPOLLIN; 83 event.data.fd = new_fd; 84 epoll_ctl(epfd,EPOLL_CTL_DEL,new_fd,&event); 85 break; 86 } 87 ret = send(new_fd,buf,strlen(buf)-1,0); 88 if(ret == -1){ 89 perror("send"); 90 return -1; 91 } 92 } 93 //new_fd 读客户端的数据 94 if(evs[i].data.fd == new_fd){ 95 memset(buf,0,sizeof(buf)); 96 ret = recv(new_fd,buf,sizeof(buf),0); 97 if(ret == -1){ 98 perror("recv"); 99 return -1; 100 }else if(ret == 0){ 101 printf("bye bye\n"); 102 close(new_fd); 103 //删除new_fd 104 memset(&event,0,sizeof(event)); 105 event.events = EPOLLIN; 106 event.data.fd = new_fd; 107 epoll_ctl(epfd,EPOLL_CTL_DEL,new_fd,&event); 108 break; 109 } 110 printf("%s\n",buf); 111 } 112 } 113 } 114 } 115 close(sfd);//关闭sfd 116 close(new_fd);//关闭new_fd 117 close(epfd);//关闭epfd 118 return 0; 119 }

 //客户端代码(客户端并未使用epoll,有兴趣的可以自己进行修改)
1
#include"func.h" 2 3 int main(int argc,char *argv[]){ 4 //socket 5 int sfd = socket(AF_INET,SOCK_STREAM,0); 6 if(sfd == -1){ 7 perror("socket"); 8 return -1; 9 } 10 //connect 11 int ret; 12 struct sockaddr_in ser; 13 memset(&ser,0,sizeof(ser)); 14 ser.sin_family = AF_INET; 15 ser.sin_addr.s_addr = inet_addr(argv[1]); 16 ser.sin_port = htons(atoi(argv[2])); 17 ret = connect(sfd,(struct sockaddr*)&ser,sizeof(ser)); 18 if(ret == -1){ 19 perror("connect"); 20 return -1; 21 } 22 printf("i am client\n"); 23 char buf[128]={0}; 24 fd_set rdset; 25 while(1){ 26 FD_ZERO(&rdset); 27 FD_SET(0,&rdset); 28 FD_SET(sfd,&rdset); 29 ret = select(sfd+1,&rdset,NULL,NULL,NULL); 30 if(ret > 0){ 31 if(FD_ISSET(0,&rdset)){ 32 memset(buf,0,sizeof(buf)); 33 ret = read(0,buf,sizeof(buf)); 34 if(ret <= 0){ 35 printf("bye bye\n"); 36 break; 37 } 38 ret = send(sfd,buf,strlen(buf)-1,0); 39 if(ret == -1){ 40 perror("send"); 41 return -1; 42 } 43 } 44 if(FD_ISSET(sfd,&rdset)){ 45 memset(buf,0,sizeof(buf)); 46 ret = recv(sfd,buf,sizeof(buf),0); 47 if(ret == -1){ 48 perror("recv"); 49 return -1; 50 }else if(ret == 0){ 51 printf("bye bye\n"); 52 break; 53 } 54 printf("%s\n",buf); 55 } 56 } 57 } 58 close(sfd); 59 60 return 0; 61 }

 






以上是关于Linux 即时聊天系统(tcp)epoll 版的主要内容,如果未能解决你的问题,请参考以下文章

Linux06

基于EPOLL模型的局域网聊天室和Echo服务器

epoll实现TCP通信

Linux网络编程——多路复用之epoll

简单通讯聊天 群聊功能 Windows下的客户端 Linux下的epoll服务器

linux下C++ socket网络编程——即时通信系统(含源码)