网络通信模型(IO模型)

1、概念

《Unix网络编程:卷1》中介绍了5种I/O模型,JAVA作为运行在宿主机上的程序,底层也遵循这些规则。

  • 阻塞式IO(Blocking IO):即传统的IO模型;
  • 非阻塞式IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK,注意这里所说的NIO并非Java的NIO(New IO)库;
  • IO多路复用(IO Multiplexing):即经典的Reactor设计模式,Java中的Selector和Linux中的epoll都是这种模型;
  • 信号驱动式IO:
  • 异步IO:即经典的Proactor设计模式,也称为异步非阻塞IO;

按POSIX标准来分,IO分为同步和异步,上面的前4种都属于同步IO。

一个IO分为两个阶段:

  1. 等待数据:数据可能来自其他应用程序或者网络,如果没有数据,操作系统就一直等待,应用程序就跟着等待;
  2. 拷贝数据:将就绪的数据拷贝到应用程序工作区;

在Unix系统中,操作系统的IO操作是一个系统调用recvfrom(),即一个系统调用recvfrom包含两步,等待数据就绪和拷贝数据。

同步和异步:描述的是用户线程与内核的交互方式。同步是指用户线程发起IO请求后需要等待或者轮询内核IO操作完成后才能继续执行。而异步是指用户线程发起IO请求后仍继续执行,当内核IO操作完成后会通知用户线程,或者调用用户线程注册的回调函数。

阻塞和非阻塞:描述的是用户线程调用内核IO操作的方式。阻塞是指IO操作需要彻底完成后才返回到用户空间。而非阻塞是指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成。

2、IO模型

2.1、blocking I/O

123820_MmEC_3787772.png

application调用 recvfrom()转入kernel,直到最后copy complete后,recvfrom()才返回,此过程一直是阻塞的。

2.2、nonblocking I/O

123837_5ySL_3787772.png

不断轮询直到内核缓冲区有数据,由于轮询会消耗大量CPU时间,这种模式并不常用。

阻塞IO与非阻塞IO的关键区别在于,系统调用recvfrom是否立即返回。

 2.3、I/O multiplexing (select/poll/epoll) 

124027_Rp5a_3787772.png

最常见的I/O复用模型,与blocking I/O相比,select会有两次系统调用,但是select能处理多个套接字,服务器只需要一两个线程就可以进行多客户端通信。

2.4、signal driven I/O (SIGIO) 

124036_xBPR_3787772.png

只有UNIX系统支持,与I/O multiplexing相比,它的优势是,免去了select的阻塞与轮询,当有活跃套接字时,由注册的handler处理。

2.5、asynchronous I/O

124044_GPo2_3787772.png

很少有*nix系统支持,windows的IOCP则是此模型,完全异步的I/O复用机制,纵观上面其它四种模型,至少都会在由kernel copy data to appliction时阻塞。而该模型是当copy完成后才通知application,可见是纯异步的。好像只有windows的完成端口是这个模型,效率也很出色。

2.6、五种模型的比较 

124123_SiEA_3787772.png

可以看出,越往后,阻塞越少,理论上效率也是最优。

3、select、poll、epoll的区别

select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。selectpollepoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。

select缺点:

a、每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大;

b、同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大;

c、select支持的文件描述符数量太小了,默认是1024;

poll

poll的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,其他的都差不多。 

epoll

select和poll的增强版本

a、 每次注册新的事件到epoll句柄中时都会拷贝进内核,保证了每个fd在整个过程中只会拷贝一次;

b、 为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表,只需在就绪链表中查看有没有就绪的fd;

c、 epoll没有这个限制,它所支持的FD上限是最大可以打开文件的数目;

 

Ref:

https://www.cnblogs.com/fysola/p/6146063.html

https://www.cnblogs.com/linganxiong/p/5583415.html

https://www.cnblogs.com/Anker/p/3265058.html

转载于:https://my.oschina.net/u/3787772/blog/1630932

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值