I/O模型解析

Linux下的系统I/O通过以下几个函数实现: open(),close(),recv(),send(),lseek(),read(),write()

要是我们在服务器程序中对监听套接字不进行非阻塞设置,那么整个程序中调用以上函数处理I/O事件默认就是阻塞的.


阻塞I/O

对于阻塞读,即调用read,recv等,将数据从内核态复制到用户态.内核缓冲区没数据就一直等,不做其他事情.有数据的话,就按照有多少读多少的原则,读完立即返回执行后面的操作.

对于阻塞写,即调用send,write等,将数据从用户态复制到内核态.因为知道要写的数据量,所以数据没完成复制的话,就一直阻塞,直到完成复制才返回.

非阻塞I/O

对于非阻塞I/O读,内核缓冲区中要是有数据,处理方法和阻塞I/O是一样的.要是没有数据的话,还是在检测完内核缓冲区后会返回一个错误码,用户可以在程序中对于不同的错误码进行决策,即是否进行再次读取操作.常见的错误吗就是errno,EWOULDBLOCK等

对于非阻塞I/O写,就是能写多少就写多少,因为有时候考虑到网络拥塞情况,写的量根据网络层的内存情况来决定,要是没有足够的空间,就会出现写不完的情况,对于阻塞I/O,写操作除非被中断,否则一直等到写完为止;而非阻塞I/O是能写多少算多少.

无论是阻塞还是非阻塞,读系统调用要是返回0的话,就表明连接已经断开.就不必进行读取了.在程序中对套接字进行以下设置使程序中系统调用成为非阻塞:

int setnonblocking(int fd) {
  int old_option = fcntl(fd, F_GETFL);
  int new_option = old_option | O_NONBLOCK;
  fcntl(fd, F_SETFL, new_option);
  return old_option;
} 

或者

recv(sockfd, buff, buff_size, MSG_DONTWAIT);
send(sockfd, buff, buff_size, MSG_DONTWAIT);

I/O复用模型

I/O复用主要是由系统调用的select和poll实现的,它们可以阻塞多个I/O操作,内核对select负责的多个socket进行监视,要是有某个socket数据准备好,select返回该套接字的可读或者可写的信息,系统调用recv来进行处理.


信号驱动式I/O

在程序中安装一个信号处理函数,当用户进程收到来自内核的数据已准备就绪的信号时,进程可以在相应的信号处理函数中调用recv进行处理.当然在没有收到信号之前,进程继续运行并不阻塞.

异步I/O

系统调用read之后,可以立即做其他的事,在内核的角度来说,当其接收到一个read之后,首先会立刻返回,所以用户进程不会阻塞,当内核将数据准备好并复制到用户内存之后,内核会通过信号来通知进程,表示这一次read已经完成.我们常说的同步I/O就不一样,要是这个I/O操作没有完成,他就使这个进程阻塞.

结合上面基本的I/O操作我们已经介绍完了,总结:

信号驱动I/O和异步I/O两者都需要内核通过信号通知进程,前者通知进程何时该通过系统调用处理来自内核的数据,即该启动一个I/O操作,而后者则是通知进程I/O操作何时完成.

区别阻塞和非阻塞的关键:进行I/O操作的系统调用是否立即返回.返回为非阻塞,否则为阻塞.

区别同步与异步:I/O操作是否使进程阻塞,阻塞是同步,否则是异步.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值