应用程序研发之网络 - 网络编程模型
3:网络编程模型-操作系统对网络编程的封装
3.1 操作系统对网络数据的处理流程
应用程序网络编程面对的都是socket,socket是操作系统对网络模型的抽象。
网络数据到达网卡,网卡做链路层解析,是自己的数据,告知cpu,cpu拷贝到socket缓冲区(内核空间),拷贝完成通知等待读取的应用程序。
3.2 阻塞非阻塞同步与异步
本处:阻塞非阻塞同步异步指操作系统层面。
应用程序进程去读取网络数据的时候分两个阶段:
阶段1:询问内核socket缓冲是否有数据(本阶段支持阻塞与非阻塞配置)
阶段2:从内核的socket缓冲区拷贝到用户程序内存
阻塞:发起读请求,如果socket缓冲区没有数据,阻塞线程,有数据后拷贝,返回(等待数据达到,达到后拷贝数据返回)。
非阻塞:读如果缓冲区有数据,拷贝,如果没有返回失败。
多路复用:阶段1一个线程可询问多个socket的状态,关注的socket状态发送变化(主要有数据可读或可写),返回。如果没有任何状态变化阻塞,只到有变化才返回。属于阻塞,不过一个线程关注多个连接,提高了效率。linux 目前主流是用epoll模式。
多路复用的select 是阻塞的。
感觉是非阻塞:应用线程读写的时候跟buffer交互,并且读的时候socket已经有数据了,读就比较快。
多路复用配合非阻塞设置:
说明:非阻塞只能是第一阶段非阻塞,第二阶段拷贝过程没有非阻塞。
使用多路复用,必须同时将socket设置为非阻塞,这样可以在第一阶段实现用一个线程去获取多个连接的状态(批量做第一阶段的事-看是否有数据)。
多路复用及两阶段
为什么只在第一阶段支持非阻塞:
网络io的时候 读写,尤其是读,对方不是不停的写,而是间歇的写。第一阶段如果阻塞会导致线程长时间占用。 而拷贝阶段是内核缓冲区拷贝到用户缓冲区。跟第一阶段相比耗时很短。也没办法拷贝过程中中断。
同理:文件类型的channel在java NIO接口中不支持设置非阻塞。就是因为文件数据本身就在本地,准备阶段的没什么耗时,所以也没必要在接口上支持非阻塞。
应用开发:连接配置为阻塞,用多路服务去select 。
同步与异步:
异步是应用线程告知内核读写后就返回,读写由操作系统完成后告知应用程序。linux目前支持不好。
上述的多路复,阻塞与非阻塞模式都属于同步。
epoll与poll
select|poll 阻塞在所有socket 上,有socket 事件时,唤醒线程,线程自己从socket列表中遍历查找有事件的socket, 如果连接不较多,每次都遍历大量的连接,性能差。
过程模型
epoll
操作系统维护一个eventpoll列表,socket有事件时将自己放入列表,唤醒线程,
线程直接从eventpoll列表里取,取到的就是有事件的socket,避免了遍历。效率高。
应用线程,jdk,系统 间调用流程。
是采用epoll还是poll,select 都是系统实现的,应用程序接口是一样的。
3.3 java NIO的封装
java NIO 的新模型
主要引入了Channel ,buffer ,Selector
buffer :
socket缓存区数据大小与应用数据不一样,buffer可方便多读写写,多次读,维护读写共用一个buffer,并互不干扰,相比于原来的流,buffer提供了对数据的结构化访问与读写位置的维护,nio上应用程序读写都在buffer上。
channel:一个channel对应一个socket
Selector:支持多路复用。
参考:
极客时间架构师训练营-李智慧
软件架构设计-余春龙
版权声明: 本文为 InfoQ 作者【superman】的原创文章。
原文链接:【http://xie.infoq.cn/article/59b804e5721c5e3910bce6f09】。文章转载请联系作者。
评论