select的限制与poll的使用

select的限制

用select实现的并发服务器,能达到的并发数一般受两方面限制:

1)一个进程能打开的最大文件描述符限制。这可以通过调整内核参数。可以通过ulimit-n(number)来调整或者使用setrlimit函数设置,但一个系统所能打开的最大数也是有限的,跟内存大小有关,可以通过cat/proc/sys/fs/file-max查看

/**示例: getrlimit/setrlimit获取/设置进程打开文件数目**/int main(){struct rlimit rl;if (getrlimit(RLIMIT_NOFILE, &rl) == -1)err_exit("getrlimit error");cout << "Soft limit: " << rl.rlim_cur << endl;cout << "Hard limit: " << rl.rlim_max << endl;cout << "————————->" << endl;rl.rlim_cur = 2048;rl.rlim_max = 2048;if (setrlimit(RLIMIT_NOFILE, &rl) == -1)err_exit("setrlimit error");if (getrlimit(RLIMIT_NOFILE, &rl) == -1)err_exit("getrlimit error");cout << "Soft limit: " << rl.rlim_cur << endl;cout << "Hard limit: " << rl.rlim_max << endl;}

2)select中的fd_set集合容量的限制(FD_SETSIZE,1024),这需要重新编译内核才能改变。

/**测试: 测试服务器端最多能够建立多少个连接server端完整源代码如下(注意使用的是<Socket编程实践(7)中的TCPServer类实现>):**/int main(){signal(SIGPIPE, sigHandlerForSigPipe);try{TCPServer server(8001);int listenfd = server.getfd();struct sockaddr_in clientAddr;socklen_t addrLen;int maxfd = listenfd;fd_set rset;fd_set allset;FD_ZERO(&rset);FD_ZERO(&allset);FD_SET(listenfd, &allset);//用于保存已连接的客户端套接字int client[FD_SETSIZE];for (int i = 0; i < FD_SETSIZE; ++i)client[i] = -1;int maxi = 0; //用于保存最大的不空闲的位置, 用于select返回之后遍历数组int count = 0;while (true){rset = allset;int nReady = select(maxfd+1, &rset, NULL, NULL, NULL);if (nReady == -1){if (errno == EINTR)continue;err_exit("select error");}if (FD_ISSET(listenfd, &rset)){addrLen = sizeof(clientAddr);int connfd = accept(listenfd, (struct sockaddr *)&clientAddr, &addrLen);if (connfd == -1)err_exit("accept error");int i;for (i = 0; i < FD_SETSIZE; ++i){if (client[i] < 0){client[i] = connfd;if (i > maxi)maxi = i;break;}}if (i == FD_SETSIZE){cerr << "too many clients" << endl;exit(EXIT_FAILURE);}//打印客户IP地址与端口号cout << "Client information: " << inet_ntoa(clientAddr.sin_addr)<< ", " << ntohs(clientAddr.sin_port) << endl;cout << "count = " << ++count << endl;//将连接套接口放入allset, 并更新maxfdFD_SET(connfd, &allset);if (connfd > maxfd)maxfd = connfd;if (–nReady <= 0)continue;}/**如果是已连接套接口发生了可读事件**/for (int i = 0; i <= maxi; ++i)if ((client[i] != -1) && FD_ISSET(client[i], &rset)){char buf[512] = {0};int readBytes = readline(client[i], buf, sizeof(buf));if (readBytes == -1)err_exit("readline error");else if (readBytes == 0){cerr << "client connect closed…" << endl;FD_CLR(client[i], &allset);close(client[i]);client[i] = -1;}cout << buf;if (writen(client[i], buf, readBytes) == -1)err_exit("writen error");if (–nReady <= 0)break;}}}catch (const SocketException &e){cerr << e.what() << endl;err_exit("TCPServer error");}}/**高并发测试端代码: contest完整源代码如下**/int main(){//最好不要修改: 不然会产生段溢出(stack-overflow)// struct rlimit rlim;// rlim.rlim_cur = 2048;// rlim.rlim_max = 2048;// if (setrlimit(RLIMIT_NOFILE, &rlim) == -1)//err_exit("setrlimit error");int count = 0;while (true){int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1){sleep(5);err_exit("socket error");}struct sockaddr_in serverAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(8001);serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");int ret = connect_timeout(sockfd, &serverAddr, 5);if (ret == -1 && errno == ETIMEDOUT){cerr << "timeout…" << endl;err_exit("connect_timeout error");}else if (ret == -1)err_exit("connect_timeout error");//获取并打印对端信息struct sockaddr_in peerAddr;socklen_t peerLen = sizeof(peerAddr);if (getpeername(sockfd, (struct sockaddr *)&peerAddr, &peerLen) == -1)err_exit("getpeername");cout << "Server information: " << inet_ntoa(peerAddr.sin_addr)<< ", " << ntohs(peerAddr.sin_port) << endl;cout << "count = " << ++count << endl;}}

Server端运行截图如图所示:

也就越容易失败,还不如怀揣一颗平常心,“但行好事,莫问前程”,往往成功的几率反而更大些

select的限制与poll的使用

相关文章:

你感兴趣的文章:

标签云: