linux网络编程之socket(十二) select函数的并发限制和poll函数应用举例
发布时间:2016-01-21 03:36:57 所属栏目:Linux 来源:网络整理
导读:一、用select实现的并发服务器,能达到的并发数,受两方面限制 1、一个进程能打开的最大文件描述符限制。 这可以通过调整内核参数。可以通过ulimit -n来调整或
poll 跟 select 还是很相似的,比较重要的区别在 于poll 所能并发的个数跟FD_SETSIZE无关,只跟一个进程所能打开的文件描述符个数有关,可以在select 程序的基础上修 改成poll 程序,在运行服务器端程序之前,使用ulimit -n 2048 将限制改成2048个,注意在运行客户端进程的终端也需更 改,因为客户端也会有所限制,这只是临时性的更改,因为子进程会继承这个环境参数,而我们是在bash命令行启动程序的 ,故在进程运行期间,文件描述符的限制为2048个。 使用poll 函数的服务器端程序如下: /************************************************************************* > File Name: echoser.c > Author: Simba > Mail: dameng34@163.com > Created Time: Fri 01 Mar 2013 06:15:27 PM CST ************************************************************************/ #include<stdio.h> #include<sys/types.h> #include<sys/socket.h> #include<unistd.h> #include<stdlib.h> #include<errno.h> #include<arpa/inet.h> #include<netinet/in.h> #include<string.h> #include<signal.h> #include<sys/wait.h> #include<poll.h> #include "read_write.h" #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while (0) int main(void) { int count = 0; signal(SIGPIPE, SIG_IGN); int listenfd; //被动套接字(文件描述符),即只可以accept, 监听套接字 if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) // listenfd = socket(AF_INET, SOCK_STREAM, 0) ERR_EXIT("socket error"); struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); */ /* inet_aton("127.0.0.1", &servaddr.sin_addr); */ int on = 1; if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) ERR_EXIT("setsockopt error"); if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) ERR_EXIT("bind error"); if (listen(listenfd, SOMAXCONN) < 0) //listen应在socket和bind之后,而在accept之前 ERR_EXIT("listen error"); struct sockaddr_in peeraddr; //传出参数 socklen_t peerlen = sizeof(peeraddr); //传入传出参数,必须有初始值 int conn; // 已连接套接字(变为主动套接字,即可以主动connect) int i; struct pollfd client[2048]; int maxi = 0; //client[i]最大不空闲位置的下标 for (i = 0; i < 2048; i++) client[i].fd = -1; int nready; client[0].fd = listenfd; client[0].events = POLLIN; while (1) { /* poll检测[0, maxi + 1) */ nready = poll(client, maxi + 1, -1); if (nready == -1) { if (errno == EINTR) continue; ERR_EXIT("poll error"); } if (nready == 0) continue; if (client[0].revents & POLLIN) { conn = accept(listenfd, (struct sockaddr *)&peeraddr, &peerlen); //accept不再阻塞 if (conn == -1) ERR_EXIT("accept error"); for (i = 1; i < 2048; i++) { if (client[i].fd < 0) { client[i].fd = conn; if (i > maxi) maxi = i; break; } } if (i == 2048) { fprintf(stderr, "too many clientsn"); exit(EXIT_FAILURE); } printf("count = %dn", ++count); printf("recv connect ip=%s port=%dn", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port)); client[i].events = POLLIN; if (--nready <= 0) continue; } for (i = 1; i <= maxi; i++) { conn = client[i].fd; if (conn == -1) continue; if (client[i].revents & POLLIN) { char recvbuf[1024] = {0}; int ret = readline(conn, recvbuf, 1024); if (ret == -1) ERR_EXIT("readline error"); else if (ret == 0) //客户端关闭 { printf("client close n"); client[i].fd = -1; close(conn); } fputs(recvbuf, stdout); writen(conn, recvbuf, strlen(recvbuf)); if (--nready <= 0) break; } } } return 0; } /* poll 只受一个进程所能打开的最大文件描述符限制,这个可以使用ulimit -n调整 */ (编辑:云计算网_泰州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
站长推荐
热点阅读