导航:首页 > 操作系统 > linuxio模型

linuxio模型

发布时间:2022-10-09 05:39:23

⑴ 为什么linux中监听套接字时最大能监听多少套接字

linux下,抛开性能上的影响,程序监听套接字的数量限制主要几个方面:

1:操作系统方面限制是句柄数量的限制,也就是65535个可用句柄去掉预先保留的,大概在5万个左右,注意文件句柄和套接字句柄是共用的,都在这65535个里面。

2:进程方面的限制,linux系统对单个进程的默认打开句柄数量限制是1024,考虑到文件操作也会占用句柄,可用于socket监听的句柄大概1000个,这个限制可以修改,不同linux版本可能有点不一样,centos是通过命令 ulimit -n 的方式去修改,要改成10240,就是

3:IO模型的限制,select模型的限制是1024,个,epoll是无限制的,完全根据上面2个的最大值。

⑵ 什么是IO模块

I/O 模块可分为离散、模拟和特殊模块等多种类型,这些模块都可以安装在带有多个插槽的导轨或者机架上,每个模块插人其中一个插槽。导轨或者机架具有不同规格,插槽数分为4、8、12 不等。一般情况下,电源模块插在第一插槽内,编号为0,PLC插在第二插槽内,各种类型的输入输出模块插在其余插槽内。I/O模块导轨的背面安装带有连接器的印制电路板,可以将插入I/O模块的各插槽连接起来,插槽的上下边可以使插入的模块排成一条直线。

(2)linuxio模型扩展阅读:

IO模块的分类:

1、RIO-8100-4DI4DO:4路开关量输入/4路计数器,4路继电器输出。

2、RIO-8100-4DI:4路开关量输入/4路计数器

3、RIO-8100-4DO:4路继电器输出。

4、RIO-8100-6DO:6路继电器输出。

5、RIO-8100-2DI5DO:2路开关量输入/2路计数器,5路继电器输出。

RIO-8100系列远程采集与控制模块,采用 RS232、RS485通信模式与上位进行数据交互。

⑶ Linux中异步IO模型有哪些

1)阻塞I/O(blocking I/O)
2)非阻塞I/O (nonblocking I/O)
3) I/O复用(select 和poll) (I/O multiplexing)
4)信号驱动I/O (signal driven I/O (SIGIO))
5)异步I/O (asynchronous I/O (the POSIX aio_functions))
其中前4种都是同步,最后一种才是异步。

⑷ Linux开发,使用多线程还是用IO复用select/epoll

多线程和用select/epoll是没有关联的,在select和epoll模型里也可以使用多线程进行io处理,select/epoll
的出现是为了解决一个线程对应一个请求时阻塞线程的问题,基于epoll的事件模型,解决了线程的阻塞问题即一个线程可以为多个请求服务

⑸ IO模型及select,poll,epoll和kqueue的区别

(一)首先,介绍几种常见的I/O模型及其区别,如下:
blocking I/O
nonblocking I/O
I/O multiplexing (select and poll)
signal driven I/O (SIGIO)
asynchronous I/O (the POSIX aio_functions)—————异步IO模型最大的特点是 完成后发回通知。
阻塞与否,取决于实现IO交换的方式。
异步阻塞是基于select,select函数本身的实现方式是阻塞的,而采用select函数有个好处就是它可以同时监听多个文件句柄.
异步非阻塞直接在完成后通知,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。

1 blocking I/O
这个不用多解释吧,阻塞套接字。下图是它调用过程的图示:

重点解释下上图,下面例子都会讲到。首先application调用 recvfrom()转入kernel,注意kernel有2个过程,wait for data和 data from kernel to user。直到最后 complete后,recvfrom()才返回。此过程一直是阻塞的。

2 nonblocking I/O:
与blocking I/O对立的,非阻塞套接字,调用过程图如下:

可以看见,如果直接操作它,那就是个轮询。。直到内核缓冲区有数据。

3 I/O multiplexing (select and poll)
最常见的I/O复用模型,select。

select先阻塞,有活动套接字才返回。与blocking I/O相比,select会有两次系统调用,但是select能处理多个套接字。

4 signal driven I/O (SIGIO)
只有UNIX系统支持,感兴趣的课查阅相关资料

与I/O multiplexing (select and poll)相比,它的优势是,免去了select的阻塞与轮询,当有活跃套接字时,由注册的handler处理。

5 asynchronous I/O (the POSIX aio_functions)
很少有*nix系统支持,windows的IOCP则是此模型

完全异步的I/O复用机制,因为纵观上面其它四种模型,至少都会在由kernel data to appliction时阻塞。而该模型是当完成后才通知application,可见是纯异步的。好像只有windows的完成端口是这个模型,效率也很出色。
6 下面是以上五种模型的比较

可以看出,越往后,阻塞越少,理论上效率也是最优。
=====================分割线==================================
5种模型的比较比较清晰了,剩下的就是把select,epoll,iocp,kqueue按号入座那就OK了。
select和iocp分别对应第3种与第5种模型,那么epoll与kqueue呢?其实也于select属于同一种模型,只是更高级一些,可以看作有了第4种模型的某些特性,如callback机制。
为什么epoll,kqueue比select高级?
答案是,他们无轮询。因为他们用callback取代了。想想看,当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,那就避免了轮询,这正是epoll与kqueue做的。
windows or *nix (IOCP or kqueue/epoll)?

诚然,Windows的IOCP非常出色,目前很少有支持asynchronous I/O的系统,但是由于其系统本身的局限性,大型服务器还是在UNIX下。而且正如上面所述,kqueue/epoll 与 IOCP相比,就是多了一层从内核数据到应用层的阻塞,从而不能算作asynchronous I/O类。但是,这层小小的阻塞无足轻重,kqueue与epoll已经做得很优秀了。
提供一致的接口,IO Design Patterns
实际上,不管是哪种模型,都可以抽象一层出来,提供一致的接口,广为人知的有ACE,Libevent(基于reactor模式)这些,他们都是跨平台的,而且他们自动选择最优的I/O复用机制,用户只需调用接口即可。说到这里又得说说2个设计模式,Reactor and Proactor。见:Reactor模式--VS--Proactor模式。Libevent是Reactor模型,ACE提供Proactor模型。实际都是对各种I/O复用机制的封装。
java nio包是什么I/O机制?
现在可以确定,目前的java本质是select()模型,可以检查/jre/bin/nio.dll得知。至于java服务器为什么效率还不错。。我也不得而知,可能是设计得比较好吧。。-_-。
=====================分割线==================================
总结一些重点:
只有IOCP是asynchronous I/O,其他机制或多或少都会有一点阻塞。
select低效是因为每次它都需要轮询。但低效也是相对的,视情况而定,也可通过良好的设计改善
epoll, kqueue、select是Reacor模式,IOCP是Proactor模式。
java nio包是select模型。。
(二)epoll 与select的区别

1. 使用多进程或者多线程,但是这种方法会造成程序的复杂,而且对与进程与线程的创建维护也需要很多的开销。(Apache服务器是用的子进程的方式,优点可以隔离用户) (同步阻塞IO)

2.一种较好的方式为I/O多路转接(I/O multiplexing)(貌似也翻译多路复用),先构造一张有关描述符的列表(epoll中为队列),然后调用一个函数,直到这些描述符中的一个准备好时才返回,返回时告诉进程哪些I/O就绪。select和epoll这两个机制都是多路I/O机制的解决方案,select为POSIX标准中的,而epoll为Linux所特有的。

区别(epoll相对select优点)主要有三:
1.select的句柄数目受限,在linux/posix_types.h头文件有这样的声明:#define __FD_SETSIZE 1024 表示select最多同时监听1024个fd。而epoll没有,它的限制是最大的打开文件句柄数目。

2.epoll的最大好处是不会随着FD的数目增长而降低效率,在selec中采用轮询处理,其中的数据结构类似一个数组的数据结构,而epoll是维护一个队列,直接看队列是不是空就可以了。epoll只会对"活跃"的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么,只有"活跃"的socket才会主动的去调用 callback函数(把这个句柄加入队列),其他idle状态句柄则不会,在这点上,epoll实现了一个"伪"AIO。但是如果绝大部分的I/O都是“活跃的”,每个I/O端口使用率很高的话,epoll效率不一定比select高(可能是要维护队列复杂)。

3.使用mmap加速内核与用户空间的消息传递。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。

关于epoll工作模式ET,LT

epoll有两种工作方式
ET:Edge Triggered,边缘触发。仅当状态发生变化时才会通知,epoll_wait返回。换句话,就是对于一个事件,只通知一次。且只支持非阻塞的socket。
LT:Level Triggered,电平触发(默认工作方式)。类似select/poll,只要还有没有处理的事件就会一直通知,以LT方式调用epoll接口的时候,它就相当于一个速度比较快的poll.支持阻塞和不阻塞的socket。

三 Linux并发网络编程模型

1 Apache 模型,简称 PPC ( Process Per Connection ,):为每个连接分配一个进程。主机分配给每个连接的时间和空间上代价较大,并且随着连接的增多,大量进程间切换开销也增长了。很难应对大量的客户并发连接。
2 TPC 模型( Thread Per Connection ):每个连接一个线程。和PCC类似。
3 select 模型:I/O多路复用技术。
.1 每个连接对应一个描述。select模型受限于 FD_SETSIZE即进程最大打开的描述符数linux2.6.35为1024,实际上linux每个进程所能打开描数字的个数仅受限于内存大小,然而在设计select的系统调用时,却是参考FD_SETSIZE的值。可通过重新编译内核更改此值,但不能根治此问题,对于百万级的用户连接请求 即便增加相应 进程数, 仍显得杯水车薪呀。
.2select每次都会扫描一个文件描述符的集合,这个集合的大小是作为select第一个参数传入的值。但是每个进程所能打开文件描述符若是增加了 ,扫描的效率也将减小。
.3内核到用户空间,采用内存复制传递文件描述上发生的信息。
4 poll 模型:I/O多路复用技术。poll模型将不会受限于FD_SETSIZE,因为内核所扫描的文件 描述符集合的大小是由用户指定的,即poll的第二个参数。但仍有扫描效率和内存拷贝问题。
5 pselect模型:I/O多路复用技术。同select。
6 epoll模型:
.1)无文件描述字大小限制仅与内存大小相关
.2)epoll返回时已经明确的知道哪个socket fd发生了什么事件,不用像select那样再一个个比对。
.3)内核到用户空间采用共享内存方式,传递消息。
四 :FAQ
1、单个epoll并不能解决所有问题,特别是你的每个操作都比较费时的时候,因为epoll是串行处理的。 所以你有还是必要建立线程池来发挥更大的效能。
2、如果fd被注册到两个epoll中时,如果有时间发生则两个epoll都会触发事件。
3、如果注册到epoll中的fd被关闭,则其会自动被清除出epoll监听列表。
4、如果多个事件同时触发epoll,则多个事件会被联合在一起返回。
5、epoll_wait会一直监听epollhup事件发生,所以其不需要添加到events中。
6、为了避免大数据量io时,et模式下只处理一个fd,其他fd被饿死的情况发生。linux建议可以在fd联系到的结构中增加ready位,然后epoll_wait触发事件之后仅将其置位为ready模式,然后在下边轮询ready fd列表。

⑹ 同步与异步,阻塞与非阻塞的区别,以及select,poll和epoll

异步的概念和同步相对。
(1)当一个同步调用发出后,调用者要一直等待返回消息(结果)通知后,才能进行后续的执行;

(2)当一个异步过程调用发出后,调用者不能立刻得到返回消息(结果)。实际处理这个调用的部件在完成后,通过 状态、通知和回调 来通知调用者。

这里提到执行部件和调用者通过三种途径返回结果:状态、通知和回调。使用哪一种通知机制,依赖于执行部件的实现,除非执行部件提供多种选择,否则不受调用者控制。

(A)阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务

(B)非阻塞调用是指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回

场景比喻:
举个例子,比如我去银行办理业务,可能会有两种方式:

在上面的场景中,如果:
a)如果选择排队(同步),且排队的时候什么都不干(线程被挂起,什么都干不了),是同步阻塞模型;
b)如果选择排队(同步),但是排队的同时做与办银行业务无关的事情,比如抽烟,(线程没有被挂起,还可以干一些其他的事),是同步非阻塞模型;
c)如果选择拿个小票,做在位置上等着叫号(通知),但是坐在位置上什么都不干(线程被挂起,什么都干不了),这是异步阻塞模型;
d)如果选择那个小票,坐在位置上等着叫号(通知),但是坐着的同时还打电话谈生意(线程没有被挂起,还可以干其他事情),这是异步非阻塞模型。

对这四种模型做一个总结:
1:同步阻塞模型,效率最低,即你专心排队,什么都不干。
2:异步阻塞,效率也非常低,即你拿着号等着被叫(通知),但是坐那什么都不干
3:同步非阻塞,效率其实也不高,因为涉及到线程的来回切换。即你在排队的同时打电话或者抽烟,但是你必须时不时得在队伍中挪动。程序需要在排队和打电话这两种动作之间来回切换,系统开销可想而知。
4:异步非阻塞,效率很高,你拿着小票在那坐着等叫号(通知)的同时,打电话谈你的生意。

linux下几个基本概念
1:用户控件和内核空间。 现代操作系统都是采用虚拟存储器,在32位操作系统下,它的寻址空间(虚拟存储空间)为4G(2的32次方)。为了保证用户进程补鞥呢直接操作内核,保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。对linux操作系统而言,将最高的1G字节空间分给了内核使用,称为内核空间,将较低的3G字节的空间划分为用户空间。

2:进程切换很耗资源 ,为了控制进程的执行,内核必须有能力挂起正在cpu上运行的进程,并恢复以前挂起的某个进程的执行,这种行为叫进程的切换。每次切换,要保存上一个的上下文环境等等,总之记住进程切换很耗资源。

3:文件描述符 :文件描述符在形式上是一个非负整数。实际上,他是一个索引,指向内核为每个进程所维护的该进程打开文件的记录表。当程序打开一个文件时,内核就会向进程返回一个非负整数的文件描述符。但是文件描述符一般在unix,linux系统中才讲。

缓存IO ,大多数系统的默认IO操作都是缓存IO,在linux的缓存IO机制中,操作系统会将IO的数据缓存在系统的页缓存(page cache)中,也就是说,数据会先被拷贝到操作系统内核的缓冲区,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。 缓存IO的缺点: 数据在传输过程中需要在应用程序和地址空间和内核进行多次数据拷贝操作,这种数据拷贝操作锁带来的cpu以及内存消耗是很大的。

LINUX的IO模型
网络IO的本质是socket的读取。socket在linux系统被抽象为流,故对网络IO的操作可以理解为对流的操作。

对于一次IO访问,比如以read操作为例, 数据会先被拷贝到操作系统内核的缓冲区,然后才会从内核缓冲区拷贝到进程的用户层,即应用程序的地址空间 。故当一个read操作发生时,其实是经历了两个阶段:
1:内核缓冲区的数据就位
2:数据从内核缓冲区拷贝到用户程序地址空间

那么具体到socket io的一次read操来说,这两步分别是:
1:等待网络上的数据分组到达,然后复制到内核缓冲区中
2:数据从内核缓冲区拷贝到用户程序的地址空间(缓冲区)

所以说 网络应用要处理的无非就两个问题:网络IO和数据计算 ,一般来说网络io带来的延迟影响比较大。

网络IO的模型大致有如下几种:

熟悉不? 我们常说的select,poll和epoll就是属于同步模型中多路复用IO的不同实现方法罢了。 下面分别对同步阻塞,同步不阻塞,同步io复用进行说明。

一:同步阻塞
它是最简单也最常用的网络IO模型。linux下默认的socket都是blocking的。

从图中可以看到,用户进程调用recvfrom这个系统调用后,就处于阻塞状态。然后kernel就开始了IO的第一个阶段:数据准备。等第一个阶段准备完成之后,kernel开始第二阶段,将数据从内核缓冲区拷贝到用户程序缓冲区(需要花费一定时间)。然后kernel返回结果(确切的说是recvfrom这个系统调用函数返回结果),用户进程才结束blocking,重新运行起来。
总结 同步阻塞模型下,用户程序在kernel执行io的两个阶段都被blocking住了 。但是优点也是因为这个,无延迟能及时返回数据,且程序模型简单。

二:同步非阻塞
同步非阻塞就是隔一会瞄一下的轮询方式。同步非阻塞模式其实是可以看做一小段一小段的同步阻塞模式。

三:IO多路复用
由于同步非阻塞方式需要不断的轮询,光轮询就占据了很大一部分过程,且消耗cpu资源。而这个用户进程可能不止对这个socket的read,可能还有对其他socket的read或者write操作,那人们就想到了一次轮询的时候,不光只查询询一个socket fd,而是在一次轮询下,查询多个任务的socket fd的完成状态,只要有任何一个任务完成,就去处理它。而且,轮询人不是进程的用户态,而是有人帮忙就好了。那么这就是所谓的 IO多路复用 。总所周知的linux下的select,poll和epoll就是这么干的。。。

selelct调用是内核级别的,selelct轮询相比较同步非阻塞模式下的轮询的区别为: 前者可以等待多个socket,能实现同时对多个IO端口的监听 ,当其中任何一个socket数据准备好了,就返回可读。 select或poll调用之后,会阻塞进程 ,与blocking IO 阻塞不用在于,此时的select不是等到所有socket数据达到再处理,而是某个socket数据就会返回给用户进程来处理。
其实select这种相比较同步non-blocking的效果在单个任务的情况下可能还更差一些 ,因为这里调用了select和recvfrom两个system call,而non-blocking只调用了一个recvfrom,但是 用select的优势在于它可以同时处理多个socket fd

在io复用模型下,对于每一个socket,一般都设置成non-blocking,但是其实 整个用户进程是一直被block的 ,只不过用户process不是被socket IO给block住,而是被select这个函数block住的。

与多进程多线程技术相比,IO多路复用的最大优势是系统开销小。

一:select
select函数监视多个socket fs,直到有描述符就绪或者超时,函数返回。当select函数返回后,可以通过遍历fdset,来找到就绪的描述符。select的基本流程为:

二:poll
poll本质上跟select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd的状态,如果某个fd的状态为就绪,则将此fd加入到等待队列中并继续遍历。如果遍历完所有的fd后发现没有就绪的,则挂起当前进程,直到设备就绪或者主动超时。被唤醒后它又要再次遍历fd。
特点:
1:poll没有最大连接数限制,因为它是用基于链表来存储的,跟selelct直接监听fd不一样。
2:同样的大量的fd的数组被整体复制与用户态和内核地址空间之间。
3:poll还有一个特点是水平触发:如果报告了fd后没有被处理,则下次poll时还会再次报告该fd。
4:跟select一样,在poll返回后,还是需要通过遍历fdset来获取已经就绪的socket。当fd很多时,效率会线性下降。

三:epoll

epoll支持水平触发和边缘触发,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就绪态,并且只会通知一次。还有一个特点是,epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。

没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口)。

效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。

内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销。

聊聊同步、异步、阻塞与非阻塞
聊聊Linux 五种IO模型
聊聊IO多路复用之select、poll、epoll详解

⑺ java网络io模型有几种

#BIO---Blocking IO
- 每个socket一个线程,读写时线程处于阻塞状态。
优点:实现简单
缺点:无法满足高并发,高接入的需求

- 不使用线程池的BIO模型,除了无法满足高并发需求外,由于需要为每个请求创建一个线程,还可能因为接入大量不活跃连接而耗尽服务器资源。

- 使用线程池的BIO模型,虽然控制了线程数量,但由于其本质上读写仍是阻塞的,仍无法满足高并发需求。

#NIO---Non-Blocking IO(非阻塞IO)
##非阻塞IO和多路复用
非阻塞IO和多路复用实际上是两个不用的概念,由于两者通常结合在一起使用,因此两者往往被混为一谈。下面我将试着分清这两个概念:
###非阻塞IO
与BIO相对应,非阻塞IO的读写方法无论是否有数据都立即返回,因此可以通过轮询方式来实现,但轮询方式的效率并不比BIO有显着提高,因为每个连接仍然需要占用一个线程。下面是轮询方式实现的IO模式图:

###多路复用
- 多路复用结合非阻塞IO能够明显提高IO的效率,这也是Java1.4把非阻塞IO和多路复用同时发布的原因。
- 多路复用的核心是多路复用器(Selector),它是需要操作系统底层支持的,简单的说,就是进程把多个socket和它们关心的事件(比如连接请求或数据已准备好)都注册在多路复用器上,操作系统会在事件发生时通知多路复用器,这样进程就可以通过多路复用器知道在那个socket上发生了什么时间,从而进行对应的处理。
- 多路复用的优点在于只需要一个线程监测(阻塞或轮询方式均可)多路选择器的状态,只有在有事件需要发生时才会真正的创建线程进行处理,因此更适合高并发多接入的应用环境。

- 在Linux系统下,多路复用的底层实现是epoll方法,与select/poll的顺序扫描不同,epoll采用效率更高的事件驱动方式,而且epoll方式并没有socket个数限制。
##BIO和NIO的比较
- BIO适用于连接长期保持的应用,比如一个复杂系统中模块之间通过长连接来进行通信。
- NIO加多路复用的模式更适合短连接、高并发、多接入的情形,比如网络服务器。
##NIO网络编程的常用接口
##Reactor模式
Reactor模式用于解决事件分发处理的问题,Handler把自己的channel和关注的事件注册到Selector中,当对应的事件发生在自己的channel上时,对应的handler就会得到通知并进行处理。
- 单线程的Reactor
消息的分发、读写、处理都在一个线程中处理,是Reactor最简单的实现方式,如果消息的处理需要较长时间,会影响效率。

```java

//Reactor类,负责分发事件并调用对应的handler
class Reactor implements Runnable {

final Selector selector;

final ServerSocketChannel serverSocket;

//Reactor初始化

Reactor(int port) throws IOException {

selector = Selector.open();

serverSocket = ServerSocketChannel.open();

serverSocket.socket().bind(new InetSocketAddress(port));

serverSocket.configureBlocking(false); //必须配置为非阻塞

//Acceptor会在Reactor初始化时就注册到Selector中,用于接受connect请求
SelectionKey sk = serverSocket.register(selector, SelectionKey.OP_ACCEPT);

sk.attach(new Acceptor()); //attach callback object, Acceptor

}

//分发消息并调用对应的handler
public void run() {
try {

while (!Thread.interrupted()) {

selector.select();

Set selected = selector.selectedKeys();

Iterator it = selected.iterator();

while (it.hasNext())

dispatch((SelectionKey)(it.next()); //Reactor负责dispatch收到的事件

selected.clear();

}

} catch (IOException ex) { /* ... */ }

}

void dispatch(SelectionKey k) {

Runnable r = (Runnable)(k.attachment()); //调用之前注册的callback对象

if (r != null)

r.run();

}

//Acceptor也是一个handler,负责创建socket并把新建的socket也注册到selector中

class Acceptor implements Runnable { // inner

public void run() {

try {

SocketChannel c = serverSocket.accept();

if (c != null)

new Handler(selector, c);

}

catch(IOException ex) { /* ... */ }

}

}

}

//Concrete Handler:用于收发和处理消息。
//在当前的实现中,使用Runnable接口作为每个具体Handler的统一接口
//如果在处理时需要参数和返回值,也可以为Handler另外声明一个统一接口来代替Runnable接口
final class Handler implements Runnable {

final SocketChannel socket;

final SelectionKey sk;

ByteBuffer input = ByteBuffer.allocate(MAXIN);

ByteBuffer output = ByteBuffer.allocate(MAXOUT);

static final int READING = 0, SENDING = 1;

int state = READING;

Handler(Selector sel, SocketChannel c) throws IOException {

socket = c; c.configureBlocking(false);

// Optionally try first read now

sk = socket.register(sel, 0);

sk.attach(this); //将Handler作为callback对象

sk.interestOps(SelectionKey.OP_READ); //第二步,接收Read事件

sel.wakeup();

}

boolean inputIsComplete() { /* ... */ }

boolean outputIsComplete() { /* ... */ }

void process() { /* ... */ }

public void run() {

try {

if (state == READING) read();

else if (state == SENDING) send();

} catch (IOException ex) { /* ... */ }

}

void read() throws IOException {

socket.read(input);

if (inputIsComplete()) {

process();

state = SENDING;

// Normally also do first write now

sk.interestOps(SelectionKey.OP_WRITE); //第三步,接收write事件

}

}

void send() throws IOException {

socket.write(output);

if (outputIsComplete()) sk.cancel(); //write完就结束了, 关闭select key

}

}

//上面 的实现用Handler来同时处理Read和Write事件, 所以里面出现状态判断

//我们可以用State-Object pattern来更优雅的实现

class Handler { // ...

public void run() { // initial state is reader

socket.read(input);

if (inputIsComplete()) {

process();

sk.attach(new Sender()); //状态迁移, Read后变成write, 用Sender作为新的callback对象

sk.interest(SelectionKey.OP_WRITE);

sk.selector().wakeup();

}

}

class Sender implements Runnable {

public void run(){ // ...

socket.write(output);

if (outputIsComplete()) sk.cancel();

}

}

}

```
- 多线程Reacotr
处理消息过程放在其他线程中执行

```java
class Handler implements Runnable {

// uses util.concurrent thread pool

static PooledExecutor pool = new PooledExecutor(...);

static final int PROCESSING = 3;

// ...

synchronized void read() { // ...

socket.read(input);

if (inputIsComplete()) {

state = PROCESSING;

pool.execute(new Processer()); //使用线程pool异步执行

}

}

synchronized void processAndHandOff() {

process();

state = SENDING; // or rebind attachment

sk.interest(SelectionKey.OP_WRITE); //process完,开始等待write事件

}

class Processer implements Runnable {

public void run() { processAndHandOff(); }

}

}

```
- 使用多个selector
mainReactor只负责处理accept并创建socket,多个subReactor负责处理读写请求

```java
Selector[] selectors; //subReactors集合, 一个selector代表一个subReactor

int next = 0;

class Acceptor { // ...

public synchronized void run() { ...

Socket connection = serverSocket.accept(); //主selector负责accept

if (connection != null)

new Handler(selectors[next], connection); //选个subReactor去负责接收到的connection

if (++next == selectors.length) next = 0;

}

}

```
#AIO
AIO是真正的异步IO,它于JDK1.7时引入,它和NIO的区别在于:
- NIO仍然需要一个线程阻塞在select方法上,AIO则不需要
- NIO得到数据准备好的消息以后,仍然需要自己把消息复制到用户空间,AIO则是通过操作系统的支持把数据异步复制到用户空间以后再给应用进程发出信号。

⑻ 什么是“同步IO”和“异步IO”

同步IO在同一时刻只允许一个IO操作,也就是说对于同一个文件句柄的IO操作是序列化的,即使使用两个线程也不能同时对同一个文件句柄同时发出读写操作。重叠IO允许一个或多个线程同时发出IO请求。

异步IO的概念和同步IO相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。在一个CPU密集型的应用中,有一些需要处理的数据可能放在磁盘上。预先知道这些数 据的位置,所以预先发起异步IO读请求。等到真正需要用到这些数据的时候,再等待异步IO完成。使用了异步IO,在发起IO请求到实际使用数据这段时间 内,程序还可以继续做其他事情。

⑼ 什么是 IO 模型

服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种:
(1)同步阻塞IO(Blocking IO):即传统的IO模型。

(2)同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。注意这里所说的NIO并非Java的NIO(New IO)库。

(3)IO多路复用(IO Multiplexing):即经典的Reactor设计模式,有时也称为异步阻塞IO,Java中的Selector和Linux中的epoll都是这种模型。

(4)异步IO(Asynchronous IO):即经典的Proactor设计模式,也称为异步非阻塞IO。

⑽ 请比较Linux与Windows在网络编程方面的特点

找了一段,大致涉及到了您的问题:

一、socket的模式
socket一般有两种模式:同步和异步(windows网络编程技术中也可叫锁定和非锁定,Linux网络编程叫阻塞和非阻塞)。

二、socket的类型

socket一般有三种类型,基于TCP的流式套接字,基于UDP的数据报套接字和原始套接字。

三、socket的IO模型

socket
的IO模型是编程中使用socket两种模式的策略,它们适用的场合不同,在不同的操作系统上支持的模型也不同,例如windows从NT版本才开始支持
完成端口模型。Linux和Windows所支持的模型也有区别,当然也有相同的地方,可能叫法不一样,但大致思路是一样的,下面分别介绍windows
和Linux的IO模型

1、 Windows下的套接字IO模型:

A、 Select(选择)模型
用于同步socket的状态检测模型,又叫(Linux)多路复用,可以同时检测多个socket的状态

B、 WSAAsyncSelect(异步选择)模型
用于异步socket的异步事件设置,它是基于Windows消息的模型,必须先打开一个窗口,然后把窗口和socket的消息绑定,这样,在socket有消息通知时,操作系统便通知窗口,然后在窗口进行处理。

C、 WSAEventSelect(异步事件)模型

于异步socket的异步事件,它是基于网络事件的模型,先使用CreateEvent创建一个事件,然后使用WSAEventSelect进行事件绑
定,然后可以使用WaitForMultipleObject(Event)进行事件监听,可以同时监听多个事件,不光是socket的,比如可以监听使
用CreateWaitableTimer创建的Timer等。

D、 重叠IO模型

于异步socket,在创建socket时需要在创建函数WSASocket中使用WSA_FLAG_OVERLAPPED标志,然后在投递IO请求的时
候将一个Overlapped结构体指针赋给投递函数,可以使用WSAWaitForMultipleObject来监听事件,然后使用
WSAGetOverlappedResult来获取IO的状态,也可以在Overlapped结构体中使用完成例程来处理,即在投递函数中把完成例程赋
给投递函数。

E、 完成端口模型

是迄今为止最复杂的一种IO模型,当应用程序需要管理众多的套接字并且希望随着系统内安装的CPU数目的增多,应用程序的性能也可以线性增加,就可以使用
这种模型,它的原理是每个CPU可以单独负责一个线程的执行,避免线程的频繁切换。使用这种模型往往可以达到最佳的系统性能。

先需要使用CreateIOCompletePort来创建完成端口,然后将IO句柄和此端口绑定,绑定也是使用此函数,当然也可以一次完成。接着是创建
工作者线程,工作者线程会使用GetQueuedCompletionStatus进入完成端口维护的线程池,当有完成事件时,会激活一个线程。

2、 Linux下的IO模型

A、阻塞IO

B、非阻塞IO

C、IO多路复用(选择)

D、信号驱动
用于异步socket,首先设定信号处理函数,然后使用fcntl函数设定socket的拥有者,像windows下使用WSAAsncSelect设定socket的窗口一样。使用这种模型,当内核操作可以被操作的时候通知我们的应用程序

E、异步IO
当内核在所有操作完成后才会通知应用程序

四、socket的一些使用上的优化

A、缓冲区的优化,可以考虑让应用程序使用比较小的缓冲区,但同时使用多个WSARecv

B、使用socket选项SO_SNDBUF和SO_RCVBUF设置socket缓冲区大小,如果设为0,操作体系统会使用应用程序的缓冲区,这样避免了从系统缓冲区向用户区复制的开销

五、注意这些IO模型有些不光是针对socket的,其他的IO操作也可以使用,最常用使用的是WriteFile,ReadFile等函数。

其它查考网址:
http://blog.163.com/tianle_han/blog/static/6617826200821522743948/
http://blog.csdn.net/yibulianhua/article/details/5374317

阅读全文

与linuxio模型相关的资料

热点内容
安卓手机的表格里怎么打勾 浏览:407
阿里云服务器有网络安全服务吗 浏览:966
超解压兔子视频 浏览:22
单片机怎么测负脉冲 浏览:172
魅族备份的app在哪里 浏览:738
java倒三角打印 浏览:112
通达信回封板主图源码 浏览:44
战地什么服务器 浏览:299
安卓为什么老是闪退怎么办 浏览:803
乐高机器人的编程软件下载 浏览:223
工作中怎么使用加密狗 浏览:735
云服务器的后台找不到 浏览:98
php逐行写入文件 浏览:912
javaoracleweb 浏览:440
京东加密码怎么弄 浏览:467
单片机程序员培训 浏览:992
PHP商城源代码csdn 浏览:636
怎么把电脑里文件夹挪出来 浏览:693
java流程处理 浏览:685
ftp创建本地文件夹 浏览:660