Linux 网络编程(IO模型)

针对linux 操做系统的5类IO模型,阻塞式、非阻塞式、多路复用、信号驱动和异步IO进行整理,参考《linux网络编程》及相关网络资料。linux

阻塞模式编程

在socket编程(以下图)中调用以下四类函数致使阻塞:缓存

  • 读操做(read、readv、recv、recvfrom、recvmsg):当应用程序调用读函数,该系统调用进入内核态,若套接字接收缓冲区无数据则阻塞,数据到达则将接收缓冲区数据拷贝至进程缓冲区并返回。对TCP而言,一旦接收缓冲区中与数据则进程被唤醒,对UDP而言有完整的UDP报文达到进程被唤醒。
  • 写操做(write、writev、send、sendto、sendmsg):当发送缓冲区空间小于写操做要求写的数量则阻塞,该状况发生不多。对UDP而言,不存在发送缓冲区,所以不可能发送阻塞。
  • 接收链接(accept):TCP协议采用倾听套接字接收客户机链接请求,完成三次握手的TCP链接保存在倾听套接字完成队列。当accept被调用时,若完成队列为空则阻塞。当有新的TCP链接,进程被唤醒同时分配一个新的链接套接字标识这个TCP链接。
  • 创建链接(connect):TCP套接字调用connect与服务器链接时进程将阻塞,待3次握手操做完成后(内核态)进程被唤醒。

非阻塞模式服务器

针对上述四类阻塞模式的socket调用,都可经过设置的方式使其非阻塞。设置方式有两种fcntl设置套接字为O_NONBLOCK,以及ioctl设置FIONBIO。完成后其四类操做非阻塞,以下:网络

  • 读操做:缓冲区无数据,函数以错误EWOULDBLOCK返回;
  • 写操做:发送缓冲区无空间,函数以错误EWOULDBLOCK返回;
  • 接收链接:若队列中无新的链接,函数以错误EWOULDBLOCK返回;
  • 链接操做:若链接不能立刻创建,返回错误类型EINPROGRESS;

非阻塞模式在运用中采用轮询,或配合select的方式使用。异步

多路复用socket

进程定义读描述符集、写描述符集以及异常描述符集(做为select的入参),在select被调用时若是没有描述符集就绪,该select将被阻塞。当有任何一个或几个描述符就绪时,select设置描述符集,并返回就绪描述符的个数。函数

/*
* 多路复用select函数,参数定义以下
* nfds: select监视的文件句柄数,通常设置为最大文件号+1
* readfds:select监视的可读文件句柄集合
* writefds:select监视的可写文件句柄集合
* exceptfds:select监视的异常文件句柄集合
*/
int
select(nfds, readfds, writefds, exceptfds, timeout)

 注:对于监视一个描述符的状况,select与阻塞模式无区别。spa

信号驱动操作系统

信号驱动的方式属于一种异步的IO方式,进程自己不会被挂起,流程以下:

 

信号驱动的IO方式主要分如下三步操做:

signal(SIGIO,sig_handler); //设置SIGIO信号对应的处理函数
fcntl(sockfd,F_SETOWN, getpid());//设置接收SIGIO信号的进程为当前进程,该信号由sockfd句柄产生
ioctl(sockfd,FIOASYNC,&on);//容许sockfd套接字进行信号驱动的输入输出

 

 对于UDP套接字,内核在如下状况下发送信号SIGIO:

  • 套接字上接收到一个UDP数据报
  • 套接字上发生一个异步错误

对TCP套接字,内核在如下状况下发送信号SIGIO:

  • 在倾听套接字上,一个链接请求完成
  • 初始化了一个断开链接的请求
  • 断开链接请求完成
  • 一个方向的链接被关闭
  • 数据到达套接字
  • 套接字发送了数据
  • 异步错误发生

异步IO

异步IO是linux 2.6内核的标准特性,基本思想是容许进程发起不少IO操做,而不用阻塞或等待任何操做。稍后在接收到IO操做完成的通知时,再检索IO操做的结果。

aio过程的数据缓存在结构体aiocb中,该结构体定义以下:

struct aiocb
{
  int aio_fildes;               /* File desriptor.  */ int aio_lio_opcode;           /* Operation to be performed.  */int aio_reqprio;              /* Request priority offset.  */ volatile void *aio_buf;       /* Location of buffer.  */ 
  size_t aio_nbytes;            /* Length of transfer.  */struct sigevent aio_sigevent; /* Signal number and value.  */ 

 

根据posix.1b所要求,主要包括以下函数:

  • aio_read(struct aiocb* aiocbp); //进行异步读操做
  • aio_write(struct aiocb* aiocbp);//进行异步写操做
  • aio_error(struct aiocb* aiocbp);//肯定请求的状态
  • aio_return(struct aiodb* aiocbp);//读写的异步返回
相关文章
相关标签/搜索