二、echo源码2如下,main.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/epoll.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/resource.h> /*setrlimit */ #define ECHO_SERVER_PORT 1883 #define LISTEN_BACKLOG 16 #define MAX_EVENT_COUNT 32 #define BUF_SIZE 2048 #define MAXCONN 60000 int set_fdlimit() { //设置每个进程允许打开的最大文件数 //这项功能等价于linux终端命令 "ulimit -n 102400" struct rlimit rt; rt.rlim_max = rt.rlim_cur = MAXCONN; if (setrlimit(RLIMIT_NOFILE, &rt) == -1) { perror("setrlimit error"); return -1; } return 0; } int main() { //设置每个进程允许打开的最大文件数,socket if (set_fdlimit() < 0) { return -1; } int ret, i; int server_fd, client_fd, epoll_fd; int ready_count; struct sockaddr_in server_addr; struct sockaddr_in client_addr; socklen_t addr_len; struct epoll_event event; struct epoll_event* event_array; char* buf; event_array = (struct epoll_event*) malloc(sizeof(struct epoll_event)*MAX_EVENT_COUNT); buf = (char*)malloc(sizeof(char)*BUF_SIZE); memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(ECHO_SERVER_PORT); server_fd = socket(AF_INET, SOCK_STREAM, 0); if(server_fd == -1) { perror("create socket failed.\n"); return 1; } //一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。 int reuse_addr = 1; if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) == -1) { return -1; } ret = bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)); if(ret == -1) { perror("bind failed.\n"); return 1; } ret = listen(server_fd, LISTEN_BACKLOG); if(ret == -1) { perror("listen failed.\n"); return 1; } fprintf(stderr,"listen on,fd=%d\n",server_fd); epoll_fd = epoll_create(1); if(epoll_fd == -1) { perror("epoll_create failed.\n"); return 1; } event.events = EPOLLIN; event.data.fd = server_fd; ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event); if(ret == -1) { perror("epoll_ctl failed.\n"); return 1; } while(1) { ready_count = epoll_wait(epoll_fd, event_array, MAX_EVENT_COUNT, -1); if(ready_count == -1) { perror("epoll_wait failed.\n"); return 1; } for(i = 0; i < ready_count; i++) { if(event_array[i].data.fd == server_fd) { client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addr_len); if(client_fd == -1) { perror("accept failed.\n"); return 1; } event.events = EPOLLIN; event.data.fd = client_fd; ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event); if(ret == -1) { perror("epoll_ctl failed.\n"); return 1; } fprintf(stderr,"accept,fd=%d\n",client_fd); } else { ret = recv(event_array[i].data.fd, buf, BUF_SIZE, 0); if(ret <= 0) { close(event_array[i].data.fd); epoll_ctl(epoll_fd, EPOLL_CTL_DEL, event_array[i].data.fd, &event); continue; } ret = send(event_array[i].data.fd, buf, (size_t)ret, 0); if(ret == -1) { perror("send failed.\n"); } } } // for each event } // while(1) close(epoll_fd); close(server_fd); free(event_array); free(buf); return 0; }
三、客户端测试
1、工具介绍
强大的TcpServer压力测试工具源码(附突破连接限制的方法和工具)
TCP_UDP_PerformanceTest
TCPCOPY:https://github.com/session-replay-tools/tcpcopy
Apache Bench:https://httpd.apache.org/docs/2.4/programs/ab.html -- ab
Apache jmeter:https://github.com/apache/jmeter
webbench:http://home.tiscali.cz/~cz210552/webbench.html
★Windows解决端口号限制方法,修改两个注册表: (必须修改,否则测试工具作为客户端发起TCP连接,数目上不去)
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters\MaxUserPort 如果没有,则手动创建 DWord(32位) ”数值数据“改为十进制65534 或者认为适当的值。 此值表示 用户最大使用的端口数量,默认为5000。
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters\TCPTimedWaitDelay 如果没有,则手动创建 DWord(32位) ”数值数据“改为十进制30 或者你认为适当的值。 此值表示一个关闭后的端口等待多久之后可以重新使用,默认为120秒,也就是2分钟才可以重新使用。
2、实践体会
★Server Test Tool这个工具,测试完成需要按“Stop“,界面会暂时卡死,没关系,请耐心等待,千万不要强行kill进程,否则会导致资源无法正常释放。如果资源无法正常释放,会出现连接数上不去的情况,此时只能通过重启电脑可以解决。
我在公司办公电脑,使用如图配置,每1000ms发起1000个tcp连接,测试通过,可以达到ConnectTotal的数值;
但是我在家里电脑,使用如图配置,tcp连接数却怎么都上不去,始终不过万,后来我调整为OnHeartbeat模式,每1000ms发起100个tcp连接,方可达成。因为OnHeartbeat比OnTimer更省流量,另外发起连接数的频次也降下来了。看来参数很重要,与路由器带宽等的承受能力有关。不妨多尝试,找出性价比最好的参数组合。
★如果使用SSH远程访问的方式,服务器程序不能是控制台带打印信息的方式,否则客户端连接会出问题,一来TCP客户端连接数很难上的去,二来SSH软件网络很容易中断。结论,服务器程序应该使用守护进程,在后台运行。