简述五种网络I/O模型


  在介绍五种模型之前我们先来了解几个概念:

同步与异步

  同步与异步的概念描述是用户线程与内核的交互方式,其关心的是消息通信的机制
同步(Synchronous)是指用户线程发起IO请求后需要等待或者轮询内核IO操作完成后才能继续执行。
异步(Asynchronous)是指用户线程发起IO请求后仍继续执行,当内核IO完成后会通知用户线程,或者调用用户线程注册的回调函数。
  举例来说,同步的时候,假如说你去买书吧,你问老板有没有apue这本书,老板就要帮你去找,找了半天,这个半天也许几秒也许几个小时,然后找没找到回来告诉你一声。而异步的时候呢,同样是去买书,老板这时候在忙,他说等他他找到了打电话告诉你然后你就回去了。回去后老板会通过回电这种方式来告诉你找没找到书。

阻塞与非阻塞

  阻塞和非阻塞的概念描述的是用户线程调用内核IO操作的方式,其关注的是程序在等待调用结果时的状态。
阻塞(Block)是指IO操作在没有接受完数据或者没有得到结果之前不会返回,需彻底完成后返回用户空间。
非阻塞(Unblock)是指IO操作被调用后立即返回一个状态值,无需等到操作完成。
  还是上面的例子来说:如果是阻塞式的,你打电话去问老板有没有apue,在老板没有告诉你之前(返回结果)你是不会挂掉电话的。如果是非阻塞式的你会觉得在这里等很浪费找时间,你他没有给你答复的时间你就该干嘛干嘛去,过再来看老板给没给你回复(返回结果)。
  借用《Unix网络编程》的模型图片来解释网络I/O的五种模型:

(一)阻塞IO模型(Blocking I/O)

        在这里插入图片描述
  阻塞IO模型(Blocking I/O):这可能是我们最容易想到的一种网络模型,再linux默认情况下所有socket就是阻塞式的,从图中我们可以了解到当用户进程调用了recvfrom这个系统调用时,内核(kernel)就开始了准备数据阶段。而对网络的IO来说,这时候还没有数据需要处理,因此内核就需要等待数据到来,而在用户进程这边进程会被阻塞,当内核准备好数据后,就会将数据从内核拷贝到用户内存,内核返回结果,用户结成才会接触阻塞状态。
例如在刚接触网络编程中的:

fd = connect() 

write(fd)

read(fd)

close(fd)

  这些接口都是阻塞型的,read需要在write后才能执行,这个模型可以通过多线程/多进程的方式改进。

(二)非阻塞IO模型(Non-blocking I/O)

        在这里插入图片描述
  非阻塞IO模型(Non-blocking I/O):上面说过默认socket都是阻塞的,非阻塞IO是建立在阻塞IO的基础上,将socket设置为NONBLOCK,可以使用ioctl系统调用设置。从图中我们可以了解到,例如用户进程发出一个read操作时如果内核(kernel)没有准备好数据,他不会让用户进程阻塞在这里等待数据,而是返回一个错误,从用户的角度讲,只要我发起的一个操作,不管成功否都会得到一个结果,如果我用户得到了一个错误那我就知道是因为read的数据没有准备好,会再次发起read操作,这个时候内核准备好数据了,就会拷贝到用户内存中完成交互。
  但是用户这种反复请求,不断轮询消耗了大量的CPU资源,因此一般很少直接用这种模型,而是在其他模型中利用了非阻塞着一种思想。

(三)IO多路复用模型(IO muitiplexing)

        在这里插入图片描述
 IO多路复用(IO muitiplexing):该模型是建立在内核提供的多路分离函数select的基础上,使用select可以避免非阻塞中不断轮询的问题,还有代表poll,epoll。
  从图中我们可以了解到当用户调用了select函数时,整个进程会阻塞在这里,在阻塞的同时,内核会监听seletc管理的socket(用户需要进行IO操作的socket添加到select里),当其中数据到达时,socket会被激活,select返回,用户调用相应函数从内核拷贝数据到用户内存。虽然该流程和阻塞IO模型(Blocking I/O)很相似,但是select的优点在于可以在这一个阻塞的时刻监听多个socket的IO请求,而即可达到同一线程内处理多请求。而在阻塞模型则需要多进程/多线程方式来解决。

(四)信号驱动IO模型(Asynchronous IO)

        在这里插入图片描述
  信号驱动IO(Asynchronous IO):当用户发起一个read操作后,内核会首先返回,不会产生阻塞,然后等待内核准备完数据后,以SIGIO信号通知请求用户将数据拷贝到用户内存。

(五)异步IO模型(Asynchronous IO)

        在这里插入图片描述
  异步IO模型(Asynchronous IO):也称为异步非阻塞IO ,在该模型中不使用readwrite这种系统接口了,而是调用内核接口。当用户线程收到通知时,数据已经被内核读取完毕,并放在用户线程的缓冲区内,内核在IO完成后通知用户线程使用,这样用户线程就是一种非阻塞状态。windows的IOCP就是这样的模型。

相比于IO多路复用模型,信号驱动和异步IO不常用,不少高性能并发服务程序使用IO多路复用+多线程任务处理。

扫描二维码关注公众号,回复: 9620935 查看本文章

参考博客:https://blog.csdn.net/historyasamirror/article/details/5778378

发布了11 篇原创文章 · 获赞 3 · 访问量 296

猜你喜欢

转载自blog.csdn.net/weixin_42647166/article/details/104666592