linux select read阻塞_网络编程:I/O多路复用之select

前面写了一个简单的echo服务器程序,这个程序同一时刻只能服务一个客户端,在实际应用中肯定是不行的。

在unix/linux系统上,提高服务器程序的并发量有很多方法,比如:

  • 每一个客户端进来,服务器fork一个子进程专门处理这个客户端。这个问题是当客户太多时,需要fork很多进程,这对系统的压力很大。
  • 预先fork多个子进程,在fork子进程之前,先创建监听fd,这样子进程就共享这个监听fd,然后每个子进程都开始accept客户端的连接。一个客户端连接进来,就可能被其中一个子进程accept然后处理。
  • 预先创建一些线程,每accept一个客户端就扔给某个线程处理。
  • 使用非阻塞(Nonblocking)的socket,然后定时检查fd是否可读写,这种定时轮询的方式经常要做无用功,比较浪费CPU。
  • 最后一种就是我们要介绍的I/O模型:I/O多路复用,1个进程就可以同时处理大量客户端的请求。结合非阻塞socket,能最大程度的提高服务器的吞吐量。

这一篇主要研究select这个函数:

int 

这个函数总是水平触发的模式(level-triggered),现在只要简单的理解成:只要监控的fd可以读写,就总是会返回。后面介绍到epoll再来理解这个模式,这个模式相对于边缘触发(edge-triggered)更容易处理。

这个函数的一些参数说明:

  • readfds,writefds,exceptfds 这是我们要监控的fd集合,我们先设置好这三个集合,等函数返回时,内容会被修改成真正有IO的fd集合,三个参数并不用全部设置,比如不关心写和异常集合,可以传NULL
    • readfds 代表想要读的的集合
    • writefds 代表想要写的集合
    • exceptfds 在Linux上只表示有带外数据(Out-of-band data)可读。
  • fd_set 内部是一个位数组,一个fd占一个位,通过下面函数操作集合:
    • FD_CLR(fd, fd_set) 清除某个fd
    • FD_ZERO(fd_set) 清除整个集合
    • FD_SET(fd, fd_set) 设置某个fd
    • FD_ISSET(fd, fd_set) 判断fd是否在集合中
  • fd_set是一个固定长度的位数组,常量FD_SETSIZE表示这个集合的大小,Linux下通常是1024。这表明fd的值不可以大于等于FD_SETSIZE,否则会出现不可预期的错误。
  • nfds 是我们要监控的三个集合中最大的fd加1,为什么是这个值呢?原因是为了优化,如果我们不传这个nfds,那么内部实现只能从0到FD_SETSIZE判断fd是否存在,这个会影响select的效率。
  • timeout 是select的超时,如果为NULL则一直阻塞到集中的IO事件到来。
  • 如果select成功返回,返回值是三个集合的fd总数;如果返回0表示超时;如果返回-1表示出错,通过errno获得错误原因。

这个函数介绍完,我们来将之前的echo服务器改造成可以接收多个客户端请求的模式,这个例子没有使用非阻塞socket,因为那样会增加程序的复杂度:

#include 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值