赞
踩
按照服务器程序的一般原理,讲服务器结构为如下三个主要模块:
TCP/IP协议在设计和实现上并没有客户端和服务器的概念,在通信 过程中所有机器都是对等的。但由于资源(视频、新闻、软件等)都被数据提供者所垄断,所以几乎所有的网络应用程序都很自然地采用了图C/S(客户端/服务器)模型:所有客户端都通过访问服务器来获取所需的资源。
C/S模型的逻辑很简单:服务器启动后,首先创建一个(或多个)监听socket,并调用bind函数将其绑定到服务器感兴趣的端口上,然后调用listen函数等待客户连接。服务器稳定运行之后,客户端就可以调用connect函数向服务器发起连接了。由于客户连接请求是随机到达的异步事件,服务器需要使用某种I/O模型来监听这一事件。
C/S模型非常适合资源相对集中的场合,并且它的实现也很简单,但其缺点也很明显:服务器是通信的中心,当访问量过大时,可能所有客户都将得到很慢的响应。
P2P模型比C/S模型更符合网络通信的实际情况。它摒弃了以服务器为中心的格局,让网络上所有主机重新回归对等的地位。P2P模型如图所示:以实际使用的P2P模型通常带有一个专门的发现服务器。这个发现服务器通常还提供查找服务(甚至还可以提供内容服务),使每个客户都能尽快地找到自己需要的资源。
P2P模型使得每台机器在消耗服务的同时也给别人提供服务,这样资源能够充分、自由地共享。云计算机群可以看作P2P模型的一个典范。但P2P模型的缺点也很明显:当用户之间传输的请求过多时,网络的负载将加重。
从编程角度来讲,P2P模型可以看作C/S模型的扩展:每台主机既是客户端,又是服务器。
服务器程序虽然种类繁多,但是其基本框架都一样,不同之处在于逻辑处理。服务器的基本框架如下:
socket在创建的时候默认是阻塞的。我们可以给socket 系统调用的第2个参数传递SOCK_NONBLOCK标志,或者通过fcntl系统 调用的F_SETFL命令,将其设置为非阻塞的。阻塞和非阻塞的概念能应 用于所有文件描述符,而不仅仅是socket。我们称阻塞的文件描述符为 阻塞I/O,称非阻塞的文件描述符为非阻塞I/O。
显然,我们只有在事件已经发生的情况下操作非阻塞I/O(读、写等),才能提高程序的效率。因此,非阻塞I/O通常要和其他I/O通知机制一起使用,比如I/O复用和SIGIO信号。
I/O复用是最常使用的I/O通知机制。它指的是,应用程序通过I/O复用函数向内核注册一组事件,内核通过I/O复用函数把其中就绪的事件通知给应用程序。I/O复用函数本身是阻塞的,它们能提高程序效率的原因在于它们具有同时监听多个I/O事件的能力。
SIGIO信号也可以用来报告I/O事件,我们可以为一个目标文件描述符指定宿主进程,那么被指定的宿主进程将捕获到SIGIO信号。这样,当目标文件描述符上有事件发生时,SIGIO信号的信号处理函数将被触发,我们也就可以在该信号处理函数中对目标文件描述符执行非阻塞I/O操作了。
同步I/O向应用程序通知的是I/O就绪事件,而异步I/O向应用程序通知的是I/O完成事件。
随着网络设计模式的兴起,Reactor和Proactor事件处理模式应运而生。同步I/O模型通常用于实现Reactor模式,异步I/O模型则用于实现Proactor模式。不过后面我们将看到,如何使用同步I/O方式模拟出Proactor模式。
它要求主线程(I/O处理单元)只负责监听文件描述上是否有事件发生,有的话就立即将该事件通知工作线程(逻辑单元)。除此之外,主线程不做任何其他实质性的工作。读写数据,接受新的连接,以及处理客户请求均在工作线程中完成。
使用同步I/O模型实现的Reactor模式的工作流程是:
与Reactor模式不同,Proactor模式将所有I/O操作都交给主线程和内核来处理,工作线程仅仅负责业务逻辑。使用异步I/O模型实现的Proactor模式的工作流程是:
连接socket上的读写事件是通过aio_read/aio_write向内核注册的,因此内核将通过信号来向应用程序报告连接socket上的读写事件。所以,主线程中的epoll_wait调用仅能用来检测监听socket上的连接请求事件,而不能用来检测连接socket上的读写事件(跟Reactor的区别)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。