I/O复用 -- select

在TCP服务编程模块,在处理客户端连接时候,仅能一次处理一个连接,而且当一个连接建立后,就不能和其他连接交互(仅一个进程),若连接的客户端并没有交互,但是其他客户端需要发送数据,此时就不能和服务器进行交互,所以逻辑处理性能并不好。我们通过I/O复用技术,来改善TCP服务编程


I/O复用技术:在一定时间内可以将很多个套接字进行统一监听,每次只处理有事件发生的套接字
在这里插入图片描述
从图中可以看出,我们在服务器端需要一个容器来放置所有需要监听的套接字,每次只对有事件发生的套接字进行处理


select方法本身是一个系统调用接口:

int select(int maxfd,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout)

  • maxfd:所监听的文件描述符最大值加一
  • *readfds:监听读事件的文件描述符容器
  • *writefds:监听写事件的文件描述符容器
  • *exceptfds:异常事件的文件描述符容器
  • *timeout:监听时间设定
    其中的三个fd_set类型的变量,在select调用时用于记录用户想监听的所有文件描述符,返回时,内核会修改这三个变量,被修改的文件描述符代表此描述符上有事件发生,三个变量中既有被修改的也有没有被修改的,需要用户自行检测那些被修改,然后做出相应操作

select编程流程示例如下(仅示例服务器端):

  • int listenfd = CreateSocket();//此处将创建监听套接字,地址与端口号进行绑定操作封装为该函数完成

  • int fds[1024]//创建一个容器记录描述符,并且随后对该容器初始化,全部置-1,将监听套接字listenfd先插入

  • fd_set readfds//创建检测读事件的容器
    在这里插入图片描述
    fd_set结构操作如上图,如是一个文件描述符分配四个字节,但是通常这个值并不大,分配空间就会有很多浪费,所以这里操作都是位操作,例如文件描述符5,就是把0至1023位的5位置为1,代表5,所以对于这个结构有四个宏函数进行操作:

  1. FD_CLR(int fd,fd_set *set)//fd位清除
  2. FD_ISSET(int fd,fd_set *set)//fd位是否就绪
  3. FD_SET(int fd,fd_set *set)//fd位设置
  4. FD_ZERO(int fd,fd_set *set)//set清空
  • while(1){//进入循环
    FD_ZERO(&readfds);//因为每次系统内核会对其进行修改,所以要在开始对上一次的记录进行清空,然后重新添加记录

  • // 1.将所有文件描述符添加至fd_set中同时得出最大的文件描述符值
    int maxfd = Setfds();//用方法实现将数组中所有的套接字添加至fds结构中,并且得出最大文件描述符的值。由上图已经得出,在检测描述符是否就绪时,若是最大描述符值为5,那么检测时只需遍历5之前的,也就是最多六个(包括0),这样可以提高性能,所以这里需要得出最大值

  • // 2.select去监听所关注的所有文件描述符
    int n = select(maxfd +1,&readfds,NULL,NULL,NULL);//这里传入最大值+1,传入检测读事件的文件描述符,后边这里不需要用到,所以传空即可,时间传空代表永久阻塞

往下的处理是封装在一起的在DealReadyfds();
//所有的文件描述符进行遍历
//如果当前fds[i]为-1,为无效描述符,跳过

  • // 3.检测那些文件描述符有事件发生,处理有事件发生的文件描述符,无事件发生的文件描述符不做处理
    if(!FD_ISSET(fds[i],&fds))//如果不是就绪的文件描述符,跳过

  • // 4.分类处理:监听套接字处理 连接套接字处理
    if(fds[i] == listenfd)//有事件发生的是监听套接字
    accept获取一个完成连接的套接字,插入到fds数组中
    else//已经连接的套接字有数据传入
    recv / send处理

  • }//循环结束


select特点
  1. 最多监听1024个文件描述符,且文件描述符值最大为不超过1024,因为他的fd_set结构为1024位,一位记录一个文件描述符
  2. fd_set在select调用中会在线修改,每次都要重新设置
  3. 最多监听三种事件类型:读事件,写事件,异常事件
  4. 只返回就绪文件个数,没有直接表示,返回后要自行检测且时间复杂度位O(n)
  5. 内核使用轮询方式检测时间是否就绪,时间复杂的位O(n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值