自己写的epoll框架,不知道为什么listen的第二个参数必须写0,否则用robot并发连接测试的时候,发现连接完成后有大量类似下图的情况。在用telnet发送数据时,没有回显。只要服务端不重启,这个一直存在,而且后面的client再连接也收不到消息
条数刚好是listen第二个参数的大小,废话不说,知道如何解决这个问题的教教我啊!!!
上epoll.cpp的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <string> #include <errno.h> #include <sys/epoll.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> const short PORT = 9999; const int MAX_EVENT = 20; void setnonblock(int fd) { long flags = fcntl(fd, F_GETFL); if (flags < 0) { perror("fcntl F_GETFL"); return; } flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) { perror("fcntl F_SETFL"); return; } } int main() { int epfd =epoll_create(1); if (epfd < 0) { perror("epoll_create"); exit(EXIT_FAILURE); } int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket"); exit(EXIT_FAILURE); } epoll_event ev; ev.events = EPOLLIN | EPOLLET; ev.data.fd = sockfd; epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev); sockaddr_in srvAddr; socklen_t socklen = sizeof(sockaddr_in); memset(&srvAddr, 0, socklen); srvAddr.sin_family = AF_INET; srvAddr.sin_addr.s_addr = INADDR_ANY; srvAddr.sin_port = htons(PORT); int yes = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); setnonblock(sockfd); if (bind(sockfd, (sockaddr*)&srvAddr, socklen) < 0) { perror("bind"); exit(EXIT_FAILURE); } // 避免 TIME_WAIT struct linger so_linger; so_linger.l_onoff=1; so_linger.l_linger=0; setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger); // if (listen(sockfd, 10) < 0) 用10总是出现上述问题 if (listen(sockfd, 0) < 0) { perror("listen"); exit(EXIT_FAILURE); } epoll_event event[MAX_EVENT]; for (;;) { int ndfs = epoll_wait(epfd, event, MAX_EVENT, -1); if (ndfs < 0) { int errornum = errno; if (errornum != 4) printf("=========== EPOLL_WAIT: %s(%d)\n", strerror(errornum), errornum); continue; } else { printf("==========================EPOLL_WAIT num: %d ========\n", ndfs); } for (int i = 0; i < ndfs; ++i) { int activefd = event[i].data.fd; if (activefd == sockfd) { sockaddr_in cltAddr; int newfd = accept(sockfd, (sockaddr*)&cltAddr, &socklen); if (newfd < 0) { perror("accept"); continue; } setnonblock(newfd); printf("%d connect from %s\n", newfd, inet_ntoa(cltAddr.sin_addr)); ev.events = EPOLLIN | EPOLLET; ev.data.fd = newfd; epoll_ctl(epfd, EPOLL_CTL_ADD, newfd, &ev); } else if (event[i].events & EPOLLIN) { std::string recvData; char buff[1024] = { 0 }; printf("EPOLLIN\n"); bool bRecvOver = false; do { int len = recv(activefd, buff, sizeof(buff), 0); if (len < 0) { int errornum = errno; if (errornum == EAGAIN) { bRecvOver = true; break; } else if (errornum == ECONNRESET) { ev.data.fd = -1; epoll_ctl(epfd, EPOLL_CTL_DEL, activefd, &ev); close(activefd); bRecvOver = false; break; } printf("================= RECV: %s(%d)\n", strerror(errornum), errornum); ev.data.fd = -1; epoll_ctl(epfd, EPOLL_CTL_DEL, activefd, &ev); close(activefd); bRecvOver = false; break; } if (len == 0) { printf("%d disconnect\n", activefd); ev.data.fd = -1; epoll_ctl(epfd, EPOLL_CTL_DEL, activefd, &ev); close(activefd); bRecvOver = false; break; } recvData.append(buff, len); memset(buff, 0, sizeof(buff)); }while(true); if (bRecvOver) { printf("recv from %d: %s\n", activefd, recvData.c_str()); ev.data.fd = activefd; ev.events = EPOLLOUT | EPOLLET; epoll_ctl(epfd, EPOLL_CTL_MOD, activefd, &ev); } } else if (event[i].events & EPOLLOUT) { char buff[1024] = { 0 }; printf("EPOLLOUT\n"); sprintf(buff, "hello %d\n", activefd); int len = send(activefd, buff, strlen(buff), 0); if (len < 0) { int errornum = errno; printf("================= SEND: %s(%d)\n", strerror(errornum), errornum); ev.data.fd = -1; epoll_ctl(epfd, EPOLL_CTL_DEL, activefd, &ev); close(activefd); continue; } ev.data.fd = activefd; ev.events = EPOLLIN | EPOLLET; epoll_ctl(epfd, EPOLL_CTL_MOD, activefd, &ev); } else { printf("ERRORERRORERRORERROR\n"); } } } close(sockfd); return 0; } |
感觉问题也有可能出现在测试并发的程序上:
robot.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
#include <cstdio> #include <cstring> #include <unistd.h> #include <pthread.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <errno.h> #include <string.h> const int mm = 10000; const short target_port = 9999; const char* target_ip = "192.168.0.20"; //pthread_mutex_t mutex; void* func(void* arg) { int* m = (int*)arg; int mm = *m; int sockfd = socket(PF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket"); // pthread_exit(NULL); return NULL; } sockaddr_in s1; memset(&s1, 0, sizeof(sockaddr_in)); s1.sin_family = AF_INET; s1.sin_port = htons(target_port); s1.sin_addr.s_addr = inet_addr(target_ip); // int yes = 1; // setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); connect(sockfd, (sockaddr*)&s1, sizeof(sockaddr_in)); char buff[1024] = {0}; sprintf(buff, "%d", mm); // while(1) // { int len = send(sockfd, buff, strlen(buff), 0); if (len < 0) { perror("send len < 0"); return NULL; } else if (len == 0) { perror("send len == 0"); return NULL; } printf("send: %s\n", buff); memset(buff, 0, sizeof(buff)); len = recv(sockfd, buff, sizeof(buff), 0); if (len < 0) { int errornum = errno; if (errornum == EAGAIN || errornum == EINTR) { printf("errno == EAGAIN or errno == EINTR\n"); close(sockfd); return NULL; // continue; } else if (errornum == ECONNRESET) { printf("errno == ECONNRESET\n"); close(sockfd); return NULL; // break; } else { printf("errno != EAGAIN and errno != EINTR errno = %d %s\n", errornum, strerror(errornum)); close(sockfd); return NULL; // break; } } else if (len == 0) { close(sockfd); return NULL; } else { printf("recv: %s\n", buff); } // close(sockfd); // break; // } return NULL; } int main() { pthread_t pid[mm]; // pthread_mutex_init(&mutex, NULL); for (int i = 0; i < mm; ++i) { // usleep(1000); int m = i; pthread_create(&pid[i], NULL, func, (void*)&m); usleep(1000); } for (int i = 0; i < mm; ++i) { pthread_join(pid[i], NULL); } // pthread_mutex_destroy(&mutex); return 0; } |
==================== 问题已解决 ====================
问题终于解决了,EPOLLET模式下高并发连接,accept只触发一次,所以应该在把accept也放到while循环内,判断accept的返回值,返回值为-1并且errno的值为EAGAIN或EWOULDBLOCK时,说明可以退出该循环了。
下面是新的epoll.cpp的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <string> #include <errno.h> #include <sys/epoll.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> const short PORT = 9999; const int MAX_EVENT = 20; void setnonblock(int fd) { long flags = fcntl(fd, F_GETFL); if (flags < 0) { perror("fcntl F_GETFL"); return; } flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) { perror("fcntl F_SETFL"); return; } } int main() { int epfd =epoll_create(1); if (epfd < 0) { perror("epoll_create"); exit(EXIT_FAILURE); } int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket"); exit(EXIT_FAILURE); } epoll_event ev; ev.events = EPOLLIN | EPOLLET; ev.data.fd = sockfd; epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev); sockaddr_in srvAddr; socklen_t socklen = sizeof(sockaddr_in); memset(&srvAddr, 0, socklen); srvAddr.sin_family = AF_INET; srvAddr.sin_addr.s_addr = INADDR_ANY; srvAddr.sin_port = htons(PORT); int yes = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); setnonblock(sockfd); if (bind(sockfd, (sockaddr*)&srvAddr, socklen) < 0) { perror("bind"); exit(EXIT_FAILURE); } // 避免 TIME_WAIT struct linger so_linger; so_linger.l_onoff=1; so_linger.l_linger=0; setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger); if (listen(sockfd, 10) < 0) { perror("listen"); exit(EXIT_FAILURE); } epoll_event event[MAX_EVENT]; for (;;) { int ndfs = epoll_wait(epfd, event, MAX_EVENT, -1); if (ndfs < 0) { int errornum = errno; if (errornum != 4) printf("=========== EPOLL_WAIT: %s(%d)\n", strerror(errornum), errornum); continue; } else { printf("==========================EPOLL_WAIT num: %d ========\n", ndfs); } for (int i = 0; i < ndfs; ++i) { int activefd = event[i].data.fd; if (activefd == sockfd) { sockaddr_in cltAddr; while (true) { int newfd = accept(sockfd, (sockaddr*)&cltAddr, &socklen); if (newfd < 0) { if (errno == EAGAIN) { printf("accept EAGAIN\n"); break; } perror("accept"); } setnonblock(newfd); printf("%d connect from %s\n", newfd, inet_ntoa(cltAddr.sin_addr)); ev.events = EPOLLIN | EPOLLET; ev.data.fd = newfd; epoll_ctl(epfd, EPOLL_CTL_ADD, newfd, &ev); } } else if (event[i].events & EPOLLIN) { std::string recvData; char buff[1024] = { 0 }; printf("EPOLLIN\n"); bool bRecvOver = false; do { int len = recv(activefd, buff, sizeof(buff), 0); if (len < 0) { int errornum = errno; if (errornum == EAGAIN) { bRecvOver = true; break; } else if (errornum == ECONNRESET) { ev.data.fd = -1; epoll_ctl(epfd, EPOLL_CTL_DEL, activefd, &ev); close(activefd); bRecvOver = false; break; } printf("================= RECV: %s(%d)\n", strerror(errornum), errornum); ev.data.fd = -1; epoll_ctl(epfd, EPOLL_CTL_DEL, activefd, &ev); close(activefd); bRecvOver = false; break; } if (len == 0) { printf("%d disconnect\n", activefd); ev.data.fd = -1; epoll_ctl(epfd, EPOLL_CTL_DEL, activefd, &ev); close(activefd); bRecvOver = false; break; } recvData.append(buff, len); memset(buff, 0, sizeof(buff)); }while(true); if (bRecvOver) { printf("recv from %d: %s\n", activefd, recvData.c_str()); ev.data.fd = activefd; ev.events = EPOLLOUT | EPOLLET; epoll_ctl(epfd, EPOLL_CTL_MOD, activefd, &ev); } } else if (event[i].events & EPOLLOUT) { char buff[1024] = { 0 }; printf("EPOLLOUT\n"); sprintf(buff, "hello %d\n", activefd); int len = send(activefd, buff, strlen(buff), 0); if (len < 0) { int errornum = errno; printf("================= SEND: %s(%d)\n", strerror(errornum), errornum); ev.data.fd = -1; epoll_ctl(epfd, EPOLL_CTL_DEL, activefd, &ev); close(activefd); continue; } ev.data.fd = activefd; ev.events = EPOLLIN | EPOLLET; epoll_ctl(epfd, EPOLL_CTL_MOD, activefd, &ev); } else { printf("ERRORERRORERRORERROR\n"); } } } close(sockfd); return 0; } |
发表评论
要发表评论,您必须先登录。