1.先说select在多路IO中的限制:
1)linux中每个程序能够打开的最多文件描述符是有限制的。默认是1024.
可以通过ulimit -n进行查看和修改:

xcy@xcy-virtual-machine:~/test/sock10_poll$ ulimit -n
1024
xcy@xcy-virtual-machine:~/test/sock10_poll$ ulimit -n 2048  // n 这里进行修改
xcy@xcy-virtual-machine:~/test/sock10_poll$ ulimit -n
2048
xcy@xcy-virtual-machine:~/test/sock10_poll$

这就意味着我们的服务器进程最多能打开1024个文件描述符。(而且0 1 2 还已经被占用了)。
而且一般服务器还有一个监听套接字,所以当第1021个连接发起时就会失败(假定前面没有关闭)。
2)我们知道select的第2-4个参数是这个类型的fd_set。这里东西可以把它看成是数组。这个数组也是有边界的。
边界就是 FD_SETSIZE。
man select的部分截取:

NOTES
       An fd_set is a fixed size buffer.  Executing FD_CLR() or FD_SET()  with
       a value of fd that is negative or is equal to or larger than FD_SETSIZE
       will result in undefined behavior.  Moreover, POSIX requires fd to be a
       valid file descriptor.

这个数组最大就是FD_SETSIZE。超过这个数以后就会越界。
FD_SETSIZE定义在系统的头文件中(具体哪个文件我没找到),可以修改那个头文件,再重新编译内核。这样比较麻烦。
想要突破这个限制,就需要poll函数了。

2.poll函数
先看man手册(截取部分):

SYNOPSIS
       #include <poll.h>
       int poll(struct pollfd *fds, nfds_t nfds, int timeout);
DESCRIPTION
       poll()  performs a similar task to select(2): it waits for one of a set
       of file descriptors to become ready to perform I/O.

也可以用来监测多个IO。但是不会被FD_SETSIZE限制。
参数:
fds:一般是一个struct pollfd类型的数组,
nfds:要监视的描述符的数目。
timeout:超时时间,-1表示不会超时。0表示立即返回,不阻塞进程。 >0表示等待数目的毫秒数。
返回值:
-1:出错了,错误代码在errno中
0:设置了超时时间,这里表示超时了
>0:数组中fds准备好读、写、或异常的那些描述符的总数量
下面来看看struct pollfd这个结构体:

struct pollfd {
               int   fd;         /* file descriptor */
               short events;     /* requested events  请求的事件,具体哪些值见下面 */
               short revents;    /* returned events  返回的事件,有点像传出参数。哪个事件发生了就存储在这里*/
           };
       //  events和revents的值可以是下面:
       The  bits that may be set/returned in events and revents are defined in
       <poll.h>:
              POLLIN There is data to read.  //可读
              POLLPRI  
                     There is urgent data to read (e.g., out-of-band  data  on
                     TCP socket; pseudoterminal master in packet mode has seen
                     state change in slave).
              POLLOUT  // 可写
                     Writing now will not block.
              POLLRDHUP (since Linux 2.6.17)
                     Stream socket peer closed connection, or shut down  writ‐
                     ing  half  of  connection.   The _GNU_SOURCE feature test
                     macro must be defined (before including any header files)
                     in order to obtain this definition.
              POLLERR  // 出错
                     Error condition (output only).
              POLLHUP
                     Hang up (output only).
              POLLNVAL
                     Invalid request: fd not open (output only).

3.实例:
先看server端:

#include<sys/types.h>
#include<sys/socket.h>
#include<sys/select.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<poll.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<errno.h> //#define CLIENTCOUNT FD_SETSIZE
#define CLIENTCOUNT 2048 int main(int argc, char **argv)
{
int listenfd = socket(AF_INET, SOCK_STREAM, );
if(listenfd < )
{
perror("socket");
return -;
} unsigned short sport = ;
if(argc == )
{
sport = atoi(argv[]);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
printf("port = %d\n", sport);
addr.sin_port = htons(sport);
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); if(bind(listenfd, (struct sockaddr*)&addr, sizeof(addr)) < )
{
perror("bind");
return -;
} if(listen(listenfd, ) < )
{
perror("listen");
return -;
}
struct sockaddr_in connaddr;
int len = sizeof(connaddr); int i = , ret = ;
struct pollfd client[CLIENTCOUNT];
for(i = ; i<CLIENTCOUNT; i++)
client[i].fd = -; int maxi = ;
client[].fd = listenfd;
client[].events = POLLIN; int count = ;
int nready = ;
char buf[] = {};
while()
{
nready = poll(client, maxi+, -);
if(nready == -)
{
perror("select");
return -; }
if(nready == )
{
continue;
} if(client[].revents & POLLIN)
{
int conn = accept(listenfd, (struct sockaddr*)&connaddr, &len);
if(conn < )
{
perror("accept");
return -;
} char strip[] = {};
char *ip = inet_ntoa(connaddr.sin_addr);
strcpy(strip, ip);
printf("client connect, conn:%d,ip:%s, port:%d, count:%d\n", conn, strip,ntohs(connaddr.sin_port), ++count); int i = ;
for(i = ; i<CLIENTCOUNT; i++)
{
if(client[i].fd == -)
{
client[i].fd = conn;
client[i].events = POLLIN;
if(i > maxi)
maxi = i;
break;
}
}
if(i == CLIENTCOUNT)
{
printf("to many client connect\n");
exit();
}
if(--nready <= )
continue;
} for(i = ; i < CLIENTCOUNT; i++)
{
if(client[i].fd == -)
continue;
if(client[i].revents & POLLIN)
{
ret = read(client[i].fd, buf, sizeof(buf));
if(ret == -)
{
perror("read");
return -;
}
else if(ret == )
{
printf("client close remove:%d, count:%d\n", client[i], --count);
close(client[i].fd);
client[i].fd = -; // 要在这里移除
} //printf("client%d:%s\n", client[i], buf);
write(client[i], buf, sizeof(buf));
memset(buf, , sizeof(buf));
if(--nready <= )
continue;
}
}
} close(listenfd);
return ;
}

所有的client都存放在数组struct pollfd client[CLIENTCOUNT]中。每连接一个就加入到数组中。

关于这个server 的理解,可以参考这个的例子(这两个例子其实很像):http://www.cnblogs.com/xcywt/p/8087677.html

下面是client端:

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/select.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h> /*
这里是暴力测试最多能连接几个。由于进程能打开的fd的限制最多的1024.
所以这里最多是1024 - 3. 也就是连接1022个的时候就出错了
(0 1 2 已经被占用了) 设置成2048就是另外一个结果了
*/
int main(int argc, char **argv)
{
unsigned short sport = ;
if(argc == )
{
sport = atoi(argv[]);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
printf("port = %d\n", sport);
addr.sin_port = htons(sport);
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); int count = ;
while()
{
int sockfd = socket(AF_INET, SOCK_STREAM, );
if(sockfd < )
{
perror("socket");
sleep(); // 这个是为了保证连接完成
return -;
}
if(connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < )
{
perror("connect");
return -;
} struct sockaddr_in addr2;
socklen_t len = sizeof(addr2);
if(getpeername(sockfd, (struct sockaddr*)&addr2, &len) < )
{
perror("getsockname");
return -;
} printf("Server: port:%d, ip:%s, count:%d\n", ntohs(addr2.sin_port), inet_ntoa(addr2.sin_addr), ++count);
}
return ;
}

client就是暴力连接,测试能连接的最大的数目:运行:
注意运行的终端需要将能打开的最大描述符设成2048,如果不改的话看不出效果。
结果(截取部分):
server:(最多只能有2048 - 4个能连接上来,0 1 2 已经被占用,还有一个监听套接字)

......
client connect, conn:2040,ip:127.0.0.1, port:38220, count:2037
client connect, conn:2041,ip:127.0.0.1, port:38222, count:2038
client connect, conn:2042,ip:127.0.0.1, port:38224, count:2039
client connect, conn:2043,ip:127.0.0.1, port:38226, count:2040
client connect, conn:2044,ip:127.0.0.1, port:38228, count:2041
client connect, conn:2045,ip:127.0.0.1, port:38230, count:2042
client connect, conn:2046,ip:127.0.0.1, port:38232, count:2043
client connect, conn:2047,ip:127.0.0.1, port:38234, count:2044
accept: Too many open files
xcy@xcy-virtual-machine:~/test/sock10_poll$

client的(截取):

......
Server: port:8080, ip:127.0.0.1, count:2036
Server: port:8080, ip:127.0.0.1, count:2037
Server: port:8080, ip:127.0.0.1, count:2038
Server: port:8080, ip:127.0.0.1, count:2039
Server: port:8080, ip:127.0.0.1, count:2040
Server: port:8080, ip:127.0.0.1, count:2041
Server: port:8080, ip:127.0.0.1, count:2042
Server: port:8080, ip:127.0.0.1, count:2043
Server: port:8080, ip:127.0.0.1, count:2044
Server: port:8080, ip:127.0.0.1, count:2045
socket: Too many open files
xcy@xcy-virtual-machine:~/test/sock10_poll$

可以看到已经超过了1024个了。

poll可以突破FD_SETSIZE的限制,但是还是无法突破进程能打开最大文件描述符的限制。

下面命令可以查看进程能打开的最大文件描述符限制(ulimit不能设置无限大),和计算机的内存有关:

cat /proc/sys/fs/file-max

5.关于上面client的sleep(5)的作用:

如果没有sleep(5):那么client这边连接第2045的时候,进程会立即退出。就会关闭进程打开的套接字。TCP协议就会给server发送FIN段。从而server这边就会检测到有的client已经关闭了。所以server这边的count就可能会不准确了。因为有的已经关闭了,就可以再次打开。

如果加上sleep(5):就可以保证前面2044个连接都发送过去了,只是第2045个连接会失败。但是server也只能接收2044个连接。保证在关闭之前没有client的fd被关闭。

select的限制以及poll的使用的更多相关文章

  1. select、pselect、poll和epoll的区别

    select.pselect.poll和epoll函数是unix中具有I/O复用的函数.什么是I/O复用?为什么要有I/O复用?以及在什么场合下使用I/O复用?既然都具有I/O复用的功能,那这几个函数 ...

  2. UNIX环境高级编程——I/O多路转接(select、pselect和poll)

    I/O多路转接:先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已准备好进行I/O时,该函数才返回.在返回时,它告诉进程哪些描述符已准备好可以进行I/O. poll.pselect ...

  3. Socket编程实践(10) --select的限制与poll的使用

    select的限制 用select实现的并发服务器,能达到的并发数一般受两方面限制: 1)一个进程能打开的最大文件描述符限制.这可以通过调整内核参数.可以通过ulimit -n(number)来调整或 ...

  4. socket编程以及select、epoll、poll示例详解

    socket编程socket这个词可以表示很多概念,在TCP/IP协议中“IP地址 + TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP + 端口号”就称为socket.在TCP协议中,建立 ...

  5. select的限制与poll的使用

    select的限制 select的并发数受到两个限制:1.一个进程能打开的最大描述符数量;2.select中fd_set集合容量的限制(FD_SETSIZE) 关于进程的最大描述符数量: ulimit ...

  6. (转载) Linux IO模式及 select、poll、epoll详解

    注:本文是对众多博客的学习和总结,可能存在理解错误.请带着怀疑的眼光,同时如果有错误希望能指出. 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案 ...

  7. Linux下select&poll&epoll的实现原理(一)

    最近简单看了一把 linux-3.10.25 kernel中select/poll/epoll这个几个IO事件检测API的实现.此处做一些记录.其基本的原理是相同的,流程如下 先依次调用fd对应的st ...

  8. Python自动化 【第十篇】:Python进阶-多进程/协程/事件驱动与Select\Poll\Epoll异步IO

    本节内容: 多进程 协程 事件驱动与Select\Poll\Epoll异步IO   1.  多进程 启动多个进程 进程中启进程 父进程与子进程 进程间通信 不同进程间内存是不共享的,要想实现两个进程间 ...

  9. 聊聊IO多路复用之select、poll、epoll详解

    本文转载自: http://mp.weixin.qq.com/s?__biz=MzAxODI5ODMwOA==&mid=2666538922&idx=1&sn=e6b436ef ...

随机推荐

  1. 文本域、bootstrap-table显示以及MySQL三者间的换行符问题

    首先,今天在做项目的时候遇到的一个问题,如何实现文本输入换行以及在前台Bootstrap-table中显示也能够换行. 也许你马上就会想到说,用富文本编辑器,然而我们需要实现的只是文本输入以及换行功能 ...

  2. Oracle 存储过程的导出导入序列的导出

    昨天发布网站,需要将oracle的存储过程导出来,再在新的电脑加上去.登陆—>工具—>导出用户对象—>选取需要导出的存储过程—>导出 保存格式为.sql.当然利用该种方法也可以 ...

  3. linux操作系统基础篇(八)

    shell脚本的变量以及正则表达式 一.变量 含义:程序的运行就是一些列状态的变量->用变量值的变化去表示. 命名规则 以字母或下划线开头,剩下的部分可以是:字母.数字.下划线. 最好遵循下述规 ...

  4. crontab中使用python无法执行

    手动执行可以的,但是在crontab中却无法执行,在网上搜了一圈,给出的结论是将相对路径改成绝对路径. 改了之后解决这个问题. 是不是依赖某些环境变量,linux 里的 cron 只有几个基本的环境变 ...

  5. python logging模块+ 个人总结

    原文地址:http://www.cnblogs.com/sislcb/archive/2008/11/25/1340627.html 从Python2.3版本中开始引入的logging模块为应用提供了 ...

  6. 实战Excel Add-in的三种玩法

    作者:陈希章 发表于 2017年11月26日 前言 这个系列文章应该有一阵子没有更新了,原因是一如既往的多,但是根本所在是我对于某些章节其实还没有完全想好怎么写,尤其是对于Office Add-in这 ...

  7. TFboy养成记 CNN

    1/先解释下CNN的过程: 首先对一张图片进行卷积,可以有多个卷积核,卷积过后,对每一卷积核对应一个chanel,也就是一张新的图片,图片尺寸可能会变小也可能会不变,然后对这个chanel进行一些po ...

  8. 把项目中的那些恶心的无处存储的大块数据都丢到FastDFS之快速搭建

        在我们开发项目的时候,经常会遇到大块数据的问题(2M-100M),比如说保存报表中1w个人的ID号,他就像一个肿瘤一样,存储在服务器哪里都 觉得恶心,放在redis,mongodb中吧,一下子 ...

  9. 0:A+B Problem-poj

    0:A+B Problem 总时间限制:  1000ms 内存限制:  65536kB 描述 Calculate a + b 输入 Two integer a,,b (0 ≤ a,b ≤ 10) 输出 ...

  10. 杭电ACM——自我强化步骤

    第一阶段:开始入门吧!(15天,53题) http://blog.csdn.net/always2015/article/details/44966019#t0 一.输入输出练习(2天,10题) 10 ...