linux网络编程-服务器程序框架

服务器解构为三个主要模块:
I/O处理单元。
逻辑单元。
存储单元。

1.服务器模型
(1)C/S模型
所有客户端都通过访问服务器来获取所需的资源。
在这里插入图片描述
服务器启动后,首先创建一个或多个监听socket,并调用bind函数将其绑定到服务器感兴趣的端口上,然后调用listen函数等待客户连接。服务器稳定运行之后,客户端就可以调用connect函数向服务器发起连接了。由于客户连接请求是随机到达的异步事件,服务器需要使用某种I/O模型来监听这一事件。I/O模型有很多种。当监听到连接请求后,服务器就调用accept函数接受它。(这些都是网络编程API的那一章节的主要内容),并分配一个逻辑单元为新的连接服务。逻辑单元可以是新创建的子进程,子线程或者其他。逻辑单元读取客户请求,处理该请求,然后将处理结果返回给客户端。客户端收到服务器的反馈之后,可以继续向服务器发送请求,也可以立即主动关闭连接。
服务器在处理一个客户请求的同时还会继续监听其他客户的请求。
select是I/O复用模型
fork是分配的逻辑单元
在这里插入图片描述

(2)P2P模型

每台主机既是客户端又是服务端。
缺点:当用户之间传输的请求过多时,网络的负载将加重。
还需要发现服务器提供查找服务。

在这里插入图片描述
2.服务器编程框架
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3.I/O模型

针对阻塞I/O执行的系统调用可能因为无法立即完成而被操作系统挂起,直到等待的事件发生为止。
socket的基础API中,可能被阻塞的系统调用包括acdept send recv connect

针对非阻塞I/O执行的系统调用总是立即返回,而不管事件是否已经发生。如果事件没有立即发生,这些系统调用就返回-1,和出错的情况一样。我们需要根据errno来区分这两种情况。
我们只有在事件已经发生的情况下操作非阻塞I/O,才能提高程序的效率。因此,非阻塞I/O通常要和其他I/O通知机制一起使用,比如I/O复用。

I/O复用是指应用程序通过I/O复用函数向内核注册一组事件,内核通过I/O复用函数把其中就绪的事件通知给应用程序。
I/O复用函数本身是阻塞的,他们能提高程序效率的原因在于他们具有同时监听多个I/O事件的能力。

4.两种高效的事件处理模式
服务器程序通常需要处理三类事件:I/O事件 信号 定时事件

同步I/O模型常用于实现Reactor模式,异步I/O模型则用于实现Proactor模式。
(1)Reactor模式
这种模式 要求主线程只负责监听文件描述上是否有事件发生,有的话就立即将该事件通知工作线程。

使用同步I/O模型实现的Reactor模式的工作流程是:
1)主线程往epoll内核事件表中注册socket上的读就绪事件
2)主线程调用epoll_wait等待socket上有数据可读。
3)当socket上有数据可读时,epoll_wait通知主线程。主线程则将socket可读事件放入请求队列。
4)睡眠在请求队列上的某个工作线程被唤醒,它从socket读取数据,并处理客户请求,然后往epoll内核事件表中注册该socket上的写就绪事件。
5)主线程调用epoll_wait等待socket可写。
6)当socket可写时,epoll_wait通知主线程。主线程将socket可写事件放入请求队列。
7)睡眠在请求队列上的某个工作线程被唤醒,它往socket上写入服务器处理客户请求的结果。

在这里插入图片描述

(2)Proactor
这种模式将所有I/O操作都交给主线程和内核来处理,工作线程仅仅负责业务逻辑。

使用异步I/O模型实现的工作流程是:
1)主线程调用aio_ read函数向内核注册socket上的读完成事件,并告诉内核用户读缓冲区的位置,以及读操作完成时如何通知应用程序(这里以信号为例,详情请参考sigevent的man手册)。

2)主线程继续处理其他逻辑。

3)当socket上的数据被读入用户缓冲区后,内核将向应用程序发送一个信号,以通知应用程序数据已经可用。

4)应用程序预先定义好的信号处理函数选择-一个工作线程来处理客户请求。工作线程 处理完客户请求之后,调用aio_ write 函数向内核注册socket上的写完成事件,并告诉内核用 户写缓冲区的位置,以及写操作完成时如何通知应用程序( 仍然以信号为例)。

5)主线程继续处理其他逻辑。

6)当用户缓冲区的数据被写人socket之后,内核将向应用程序发送一个信号,以通知应用程序数据已经发送完毕。

7)应用程序预先定义好的信号处理函数选择-一个工作线程来做善后处理,比如决定是否关闭socket.

在这里插入图片描述
(3)使用同步I/O方式模拟出Proactor模式

主线程执行数据读写操作,读写完成之后,主线程向工作线程通知这一事件。那么从工作线程的角度来看骂他们就直接获得了数据读写的结果,接下来只是对读写的结果进行逻辑处理。

工作流程如下:
1)主线程往epoll内核时间表中注册socket上的读就绪事件。

2)主线程调用epoll_ wait 等待socket. 上有数据可读。

3)当socket.上有数据可读时,epoll_ wait 通知主线程。主线程从socket 循环读取数据,直到没有更多数据可读,然后将读取到的数据封装成-一个请求对象并插人请求队列。

4)睡眠在请求队列上的某个工作线程被唤醒,它获得请求对象并处理客户请求,然后往epoll内核事件表中注册socket上的写就绪事件。

5)主线程调用epoll_ _wait 等待socket可写。

6)当socket可写时,epoll wait通知主线程。主线程往socket上写人服务器处理客户请求的结果。

在这里插入图片描述
5.两种高效的并发模式
并发模式是指I/O处理单元和多个逻辑单元之间协调完成任务的方法。

(1)半同步/半异步模式

首先,半同步/半异步模式中的“同步”和“异步”与前面讨论的I/O模型中的“同步”和“异步”是完全不同的概念。在IO模型中,“同步”和“异步”区分的是内核向应用程序通知的是何种I/O事件(是就绪事件还是完成事件),以及该由谁来完成I/O读写(是应用.程序还是内核)。在并发模式中,“同步”指的是程序完全按照代码序列的顺序执行:“异步”指的是程序的执行需要由系统事件来驱动。常见的系统事件包括中断、信号等。

在这里插入图片描述
半同步/半异步模式中,同步线程用于处理客户逻辑,异步线程用于处理I/O事件。
异步线程监听到客户请求后,就将其封装成请求对象并插入请求队列中。请求队列将通知某个工作在同步模式的工作线程来读取并处理该请求对象。具体选用哪个工作线程,则取决于请求队列的设计。
在这里插入图片描述
半同步/半反应堆模式

这个异步线程只有一个,由主线程充当。
所有工作线程都睡眠在请求队列上,当有任务到来时,它们将通过竞争(互斥锁)获得任务的接管权。这种竞争机制使得只有空闲的工作线程才有机会来处理新任务。

(2)领导者/追随者模式

领导者/追随者模式是多个工作线程轮流获得事件源集合,轮流监听、分发并处理事件的一种模式。在任意时间点,程序都仅有一个领导者线程,它负贵监听I/O事件。而其他线程则都是追随者,它们休眠在线程池中等待成为新的领导者。当前的领导者如果检测到I/O事件,首先要从线程池中推选出新的领导者线程,然后处理I/O事件。此时,新的领导者等待新的I/O事件,而原来的领导者则处理I/O事件,二者实现了并发。

6.有限状态机
带状态转移的有限状态机
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值