Linux下socket通信和epoll

时间:2021-10-05 16:15:06

上一篇博客用多线程实现服务端和多个客户端的通信,但是在实际应用中如果服务端有高并发的需求,多线程并不是一个好选择。

实现高并发的一种方法是IO多路复用,也就是select,poll,epoll等等。

于是我采用epoll再修改了服务端,实现单线程服务多个客户端。

服务端:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <fcntl.h> // open function
  4 #include <unistd.h> // close function
  5 #include <sys/socket.h>
  6 #include <netinet/in.h>
  7 #include <string.h>
  8 #include <pthread.h>
  9 #include <errno.h>
 10 #include <sys/epoll.h>
 11 
 12 const int PORT = 8888;
 13 /*
 14     listen_loop(): epoll监听套接字,作不同处理
 15     accept_conn(): 新的客户端连接进来,执行accept,将fd加入epoll set
 16     recv_message(): recv并且重复输出一份给客户端
 17  */
 18 void listen_loop();
 19 void accept_conn(unsigned int sock_fd, unsigned int epollfd);
 20 void recv_message(unsigned int sock_fd);
 21 
 22 int main(void) {
 23     int sock_fd;
 24     struct sockaddr_in server_addr;
 25 
 26     //初始化socket
 27     sock_fd = socket(AF_INET, SOCK_STREAM, 0); 
 28     if (sock_fd < 0) {
 29         perror("socket:");
 30         return 0;
 31     }
 32 
 33     //编辑地址
 34     memset(&server_addr, 0, sizeof(server_addr));
 35     server_addr.sin_family = AF_INET;//ipv_4
 36     server_addr.sin_port = htons(PORT);//监听端口8888
 37     server_addr.sin_addr.s_addr = INADDR_ANY;//本地的任意地址
 38 
 39     //绑定然后监听
 40     if (bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
 41         perror("bind:");
 42         return 0;
 43     }
 44     if (listen(sock_fd, 10) < 0) {
 45         perror("listen");
 46         return 0;
 47     }
 48 
 49     listen_loop(sock_fd);
 50 
 51     return 0;
 52 }
 53 void accept_conn(unsigned int sock_fd, unsigned int epollfd) {
 54     struct sockaddr_in clientaddr;
 55     struct epoll_event event;
 56     socklen_t len = sizeof(struct sockaddr);
 57     int accept_fd = 0;
 58 
 59     accept_fd = accept(sock_fd, (struct sockaddr*)&clientaddr, &len);
 60 
 61     if (accept_fd <= 0) {
 62         perror("accept error");
 63         return;
 64     }
 65 
 66     //将新建连接加入epoll set
 67     event.data.fd = accept_fd;
 68     event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
 69     epoll_ctl(epollfd, EPOLL_CTL_ADD, accept_fd, &event);
 70     return;
 71 }
 72 
 73 void recv_message(unsigned int sock_fd) {
 74     char recv_buf[1024], send_buf[1024];
 75 
 76     memset(recv_buf, 0, sizeof(recv_buf));
 77     memset(send_buf, 0, sizeof(send_buf));
 78 
 79     recv(sock_fd, recv_buf, sizeof(recv_buf), 0);
 80     fputs(recv_buf, stdout);
 81     strcpy(send_buf, recv_buf);
 82     send(sock_fd, send_buf, sizeof(send_buf), 0);
 83 
 84     return;
 85 }
 86 void listen_loop(unsigned int sock_fd)
 87 {
 88     int epollfd, i, ret;
 89     int timeout = 300;
 90     struct epoll_event event;
 91     struct epoll_event eventList[10];
 92 
 93     /*创建epoll监听事件*/
 94     epollfd = epoll_create(10);
 95     event.events = EPOLLIN | EPOLLET;
 96     event.data.fd = sock_fd;
 97 
 98     /*注册epoll监听事件.*/
 99     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sock_fd, &event) < 0) {
100         printf("register epoll event err !");
101         return;
102     }
103 
104     while (1) {
105         ret = epoll_wait(epollfd, eventList, 10, timeout);
106 
107         /*epoll事件错误.*/
108         if (ret < 0) {
109             printf("epoll event err!");
110             break;
111         }
112         /*无事件返回.*/
113         else if (ret == 0) {
114             continue;
115         }
116 
117         /*epoll返回事件.*/
118         for (i = 0; i < ret; i++) {
119             /*epoll 错误*/
120             if ((eventList[i].events & EPOLLERR) || (eventList[i].events & EPOLLHUP) || !(eventList[i].events & EPOLLIN)) {
121                 printf("epoll error\n");
122                 close(eventList[i].data.fd);
123                 exit(-1);
124             }
125 
126             //half connection
127             if (eventList[i].events & EPOLLRDHUP) {
128                 printf("//one client close the conne.//\n");
129                 close(eventList[i].data.fd);
130             }
131 
132             /*accept事件*/
133             if (eventList[i].data.fd == sock_fd) {
134                 accept_conn(sock_fd, epollfd);
135             }
136             /*非sock_fd则为其他事件.*/
137             else {
138                 recv_message(eventList[i].data.fd);
139             }
140         }
141     }
142     close(epollfd);
143     close(sock_fd);
144     return;
145 }