上一篇博客用多线程实现服务端和多个客户端的通信,但是在实际应用中如果服务端有高并发的需求,多线程并不是一个好选择。
实现高并发的一种方法是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 }