文章目录
  1. 服务器编程框架
  2. I/O模型
    1. I/O复用
    2. SIGIO信号
    3. 异步I/O
    4. 小结

服务器编程框架

服务器的基本框架如下图。

 

各个模块的功能描述如下表。

 

请求队列通常被实现为池的一部分。对于服务器机群而言,请求队列是各台服务器之间预先建立的、静态的、永久的TCP连接。这种TCP连接能够提高服务器之间交换数据的效率,因为它避免了动态建立TCP连接而导致的额外系统开销。

I/O模型

(非)阻塞的文件描述符为(非)阻塞I/O。socket的基础API中,可能被阻塞的系统调用包括accept、send、recv、connect。

针对非阻塞I/O执行的系统调用总是立即返回,而不论事件是否已经发生。若事件没有立即发生,系统调用返回-1,这与出错情况一样。因此,需要根据errno来区分这两种情况。对accept、send、recv而言,事件未发生时errno通常被设置为EAGAIN或EWOULDBLOCK;对connect而言,errno则被设置为EINPROGRESS。

显然,只有在事件已经发生的情况下操作非阻塞I/O,才能提高程序的效率。因此,非阻塞I/O通常要与其他I/O通知机制一起使用,如I/O复用与SIGIO信号。

I/O复用

I/O复用是最常使用的I/O通知机制。应用程序通过I/O复用函数向内核注册一组事件,内核通过I/O复用函数将其中就绪的事件通知给应用程序。

Linux上常用的I/O复用函数有select、poll、epoll_wait;

I/O复用函数本身是阻塞的,它们能提高程序效率的原因在于它们具有同时监听多个I/O事件的能力

SIGIO信号

SIGIO信号也可以用来报告I/O事件。为目标文件描述符指定宿主进程,那么被指定的宿主进程将捕获到SIGIO信号。于是,当目标文件描述符上有事件发生时,SIGIO信号的信号处理函数将被触发,我们也就可以在该信号处理函数中对目标文件描述符执行非阻塞I/O操作。

阻塞I/O、I/O复用与信号驱动I/O都是I/O同步模型。I/O的读写操作均发生在I/O事件之后,由应用程序来完成

异步I/O

异步I/O的读写操作总是立即返回(不论I/O是否阻塞),真正的读写操作已经由内核接管。

同步I/O向应用程序通知的是I/O就绪事件,而异步I/O向应用程序通知的是I/O完成事件

小结

上面讨论的几种I/O模型的差异如下表。