前言
关于TCP服务器最大并发连接数有一种误解就是“因为端口号上限为65535,所以TCP服务器理论上的可承载的最大并发连接数也是65535”。
先说结论:对于TCP服务端进程来说,他可以同时连接的客户端数量并不受限于可用端口号。并发连接数受限于linux可打开文件数,这个数是可以配置的,可以非常大,所以实际上受限于系统性能。
现在做服务器开发不加上高并发根本没脸出门,所以为了以后吹水被别人怼“天天提高并发,你自己实现的最高并发是多少”的时候能义正言辞的怼回去,趁着元旦在家没事决定自己写个demo搞一搞。
这个测试主要是想搞明白Linux下哪些参数配置限制了连接数的最大值,上限是多少。
一、先说下demo的思路:
服务端用epoll实现,就是简简单单的接收连接,然后客户端用go的goroutine,每个goroutine就是简单的建立连接,然后什么也不做。
上代码:
server:
/* * g++ -o test_epoll ./test_epoll.c */#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/epoll.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>int SetReuseAddr(int fd){ int optval = 1; socklen_t optlen = sizeof(optval); return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen);}int main(){ int fd = socket(AF_INET, SOCK_STREAM, 0); int iRet = SetReuseAddr(fd); if (iRet != 0) { printf("setsockopt for SO_REUSEADDR failed, error:%s/n", strerror(iRet)); return iRet; } struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(8080); addr.sin_addr.s_addr = INADDR_ANY; if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { printf("bind failed, error:%s/n", strerror(errno)); return errno; } if (listen(fd, 5) == -1) { printf("listen failed, error:%s/n", strerror(errno)); return errno; } printf("Listening on 8080.../n"); int epfd = epoll_create(102400); struct epoll_event event; event.events = EPOLLIN; event.data.fd = fd; epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event); struct epoll_event revents[102400]; int iOnline = 0; while (1) { int num = epoll_wait(epfd, revents, 102400, 60 * 1000); printf("epoll_wait return %d/n", num); if (num > 0) { for (int i = 0; i < num; i++) { if (revents[i].data.fd == fd) { int client; struct sockaddr_in cli_addr; socklen_t cli_addr_len = sizeof(cli_addr); client = accept(fd, (struct sockaddr*)&cli_addr, &cli_addr_len); if (client == -1) { printf("accept failed, error:%s/n", strerror(errno)); if (errno == EMFILE) { printf("per-process limit reached/n"); exit(errno); } if (errno == ENFILE) { printf("system-wide limit reached/n"); exit(errno); } continue; } iOnline++; printf("Receive a new connection from %s:%d/n", inet_ntoa(cli_addr.sin_addr), cli_addr.sin_port); event.events = EPOLLIN; event.data.fd = client; epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event); } } } printf("Online number:%d/n", iOnline); } return 0;}
新闻热点
疑难解答