关于Linux网络编程当中的几个客户端模型总结

本节主要介绍常见的Server的并发模型,这些模型与编程语言本身无关,有的编程语言可能在语法上直接透明了模型本质,所以开发者没必要一定要基于模型去编写,只是需要知道和了解并发模型的构成和特点即可,本节的一些使用模型需要读者了解基本的多路IO复用知识,如1.1~1.6章节介绍。

1.模型一:单线程Accept(无IO复用)

模型一是单线程的Server,并且不适用任何IO复用机制,来实现一个基本的网络服务器。其结构如图10.17所示。

图1.17 网络并发模型一:单线程Accept

1) 流程

  1. 我们首选启动一个Server服务端进程,其中进程包括主线程main thread。我们知道一个基本的服务端Socket编程需要的几个关键步骤,创建一个ListenFd(服务端监听套接字),将这个ListenFd绑定到需要服务的IP和端口上,然后执行阻塞Accept被动等待远程的客户端建立链接,每次客户端Connect链接过来,main thread中accept响应并建立连接。

  2. 这里第一个链接过来的Client1请求服务端链接,服务端Server创建链接成功,得到Connfd1套接字后, 依然在main thread串行处理套接字读写,并处理业务。

  3. 在(2)处理业务中,如果有新客户端Connect过来,Server无响应,直到当前套接字全部业务处理完毕。

  4. 当前客户端处理完后,完毕链接,处理下一个客户端请求。

  5. 以上是模型一的服务端整体执行逻辑,我们来分析一下模型一的优缺点:

2)优点

模型一的socket编程流程清晰且简单,适合学习使用,可以基于模型一很快的了解socket基本编程流程。

3)缺点

该模型并非并发模型,是串行的服务器,同一时刻,监听并响应最大的网络请求量为`1`。即并发量为`1`。所以综上,仅适合学习基本socket编程,不适合任何服务器Server构建。

2.模型二:单线程Accept+多线程读写业务(无IO复用)

模型二是主进程启动一个main thread线程,其中main thread在进行socket初始化的过程和模型一是一样的,那么对于如果有新的Client建立链接请求进来,就会出现和模型一不同的地方,如图10.18所示。

图1.18 网络并发模型二:单线程Accept+多线程读写-1

1)流程

  1. 主线程main thread执行阻塞Accept,每次客户端Connect链接过来,main thread中accept响应并建立连接。

  2. 创建链接成功,得到Connfd1套接字后,创建一个新线程thread1用来处理客户端的读写业务。main thead依然回到Accept阻塞等待新客户端。

  3. thread1通过套接字Connfd1与客户端进行通信读写。

  4. server在(2)处理业务中,如果有新客户端Connect过来,main thread中Accept依然响应并建立连接,重复(2)过程,如图1.19所示。

图1.19 网络并发模型二:单线程Accept+多线程读写-2

以上是模型二的服务端整体执行逻辑,我们来分析一下模型一的优缺点:

2)优点

基于模型一:单线程Accept(无IO复用) 支持了并发的特性。使用灵活,一个客户端对应一个线程单独处理,server处理业务内聚程度高,客户端无论如何写,服务端均会有一个线程做资源响应。

3)缺点

随着客户端的数量增多,需要开辟的线程也增加,客户端与server线程数量1:1正比关系,一次对于高并发场景,线程数量收到硬件上限瓶颈。对于长链接,客户端一旦无业务读写,只要不关闭,server的对应线程依然需要保持连接(心跳、健康监测等机制),占用连接资源和线程开销资源浪费。仅适合客户端数量不大,并且数量可控的场景使用。仅适合学习基本socket编程,不适合任何服务器Server构建。

3.模型三、单线程多路IO复用

1)流程

模型三是在单线程的基础上添加多路IO复用机制,这样就减少了多开销线程的弊端,模型三的流程如下:

  • 主线程main thread创建listenFd之后,采用多路I/O复用机制(如:select、epoll)进行IO状态阻塞监控。有Client1客户端Connect请求,I/O复用机制检测到ListenFd触发读事件,则进行Accept建立连接,并将新生成的connFd1加入到监听I/O集合中,如图1.20所示。

图1.20 网络并发模型三:单线程Accept多路IO复用-1

  • Client1再次进行正常读写业务请求,main thread的多路I/O复用机制阻塞返回,会触该套接字的读/写事件等,如图10.21所示。

图1.21 网络并发模型三:单线程Accept多路IO复用-2

  • 对于Client1的读写业务,Server依然在main thread执行流程提继续执行,此时如果有新的客户端Connect链接请求过来,Server将没有即时响应,如图10.22所示。

图1.22 网络并发模型三:单线程Accept多路IO复用-3

  • 等到Server处理完一个连接的Read+Write操作,继续回到多路I/O复用机制阻塞,其他链接过来重复(2)、(3)流程。

以上是模型二的服务端整体执行逻辑,我们来分析一下模型一的优缺点:

2)优点

单流程解决了可以同时监听多个客户端读写状态的模型,不需要1:1与客户端的线程数量关系。多路I/O复用阻塞,非忙询状态,不浪费CPU资源, CPU利用率较高。

3)缺点

虽然可以监听多个客户端的读写状态,但是同一时间内,只能处理一个客户端的读写操作,实际上读写的业务并发为1。多客户端访问Server,业务为串行执行,大量请求会有排队延迟现象,当Client3占据main thread流程时,Client1,Client2流程卡在IO复用等待下次监听触发事件。

4.模型四-单线程多路IO复用+多线程读写业务(业务工作池)

模型四是基于模型三的一种改进版,但是赶紧的地方是在处理应用层消息业务本身,将这部分承担的压力交给了一个Worker Pool工作池来处理。

1)流程

  • 主线程main thread创建listenFd之后,采用多路I/O复用机制(如:select、epoll)进行IO状态阻塞监控。有Client1客户端Connect请求,I/O复用机制检测到ListenFd触发读事件,则进行Accept建立连接,并将新生成的connFd1加入到监听I/O集合中,如图10.23所示。

图1.23 网络并发模型四:单线程多路IO复用+业务工作池-1

  • 当connFd1有可读消息,触发读事件,并且进行读写消息。

  • main thread按照固定的协议读取消息,并且交给worker pool工作线程池, 工作线程池在server启动之前就已经开启固定数量的thread,里面的线程只处理消息业务,不进行套接字读写操作,如图10.24所示。

图1.24 网络并发模型四:单线程多路IO复用+业务工作池-2

  • 工作池处理完业务,触发connFd1写事件,将回执客户端的消息通过main thead写给对方,如图1.25所示。

图1.25 网络并发模型四:单线程多路IO复用+业务工作池-3

那么接下来Client2的读写请求的逻辑就是重复上述(1)-(4)的过程,一般我们把这种基于消息事件的业务层处理的线程称之为业务工作池,如图10.26所示。

图1.25 网络并发模型四:单线程多路IO复用+业务工作池-4

以上是模型四的服务端整体执行逻辑,我们来分析一下模型一的优缺点:

2)优点

对于模型三, 将业务处理部分,通过工作池分离出来,减少多客户端访问Server,业务为串行执行,大量请求会有排队延迟时间。实际上读写的业务并发为1,但是业务流程并发为worker pool线程数量,加快了业务处理并行效率。

3)缺点

读写依然为main thread单独处理,最高读写并行通道依然为1。虽然多个worker线程处理业务,但是最后返回给客户端,依旧需要排队,因为出口还是main thread的Read + Write。

5.模型五:单线程IO复用+多线程IO复用(链接线程池)

模型五是单线程IO复用机制上再加上多线程的IO复用机制,看上去很繁琐,但是这种模型确实当下最通用和高效的解决方案。

1)流程

  • Server在启动监听之前,开辟固定数量(N)的线程,用Thead Pool线程池管理,如图10.26所示。

图1.26 网络并发模型五:单线程多路IO复用+多线程IO复用-1

  • 主线程main thread创建listenFd之后,采用多路I/O复用机制(如:select、epoll)进行IO状态阻塞监控。有Client1客户端Connect请求,I/O复用机制检测到ListenFd触发读事件,则进行Accept建立连接,并将新生成的connFd1分发给Thread Pool中的某个线程进行监听。

  • Thread Pool中的每个thread都启动多路I/O复用机制(select、epoll),用来监听main thread建立成功并且分发下来的socket套接字。

图1.27 网络并发模型五:单线程多路IO复用+多线程IO复用-2

  • 如图1.27所示, thread监听ConnFd1、ConnFd2, thread2监听ConnFd3,thread3监听ConnFd4. 当对应的ConnFd有读写事件,对应的线程处理该套接字的读写及业务。

所以我们将这些固定承担epoll多路IO监控的线程集合,称之为线程池,如图1.28所示。

图1.28 网络并发模型五:单线程多路IO复用+多线程IO复用-3

以上是模型五的服务端整体执行逻辑,我们来分析一下模型一的优缺点。

2)优点

将main thread的单流程读写,分散到多线程完成,这样增加了同一时刻的读写并行通道,并行通道数量N, N为线程池Thread数量。server同时监听的ConnFd套接字数量几乎成倍增大,之前的全部监控数量取决于main thread的多路I/O复用机制的最大限制 (select 默认为1024, epoll默认与内存大小相关,约3~6w不等),所以理论单点Server最高响应并发数量为N*(3~6W)(N为线程池Thread数量,建议与CPU核心成比例1:1)。如果良好的线程池数量和CPU核心数适配,那么可以尝试CPU核心与Thread进行绑定,从而降低CPU的切换频率,提升每个Thread处理合理业务的效率,降低CPU切换成本开销。

3)缺点

虽然监听的并发数量提升,但是最高读写并行通道依然为N,而且多个身处同一个Thread的客户端,会出现读写延迟现象,实际上每个Thread的模型特征与模型三:单线程多路IO复用一致。

6.模型五(进程版):单进程多路I/O复用+多进程IO复用

模型五进程版和模型五的流程大致一样,这里的区别是由线程池更编程进程池,如图10.29所示。

图1.29 网络并发模型五-进程池版本-1

在模型五进程版要注意的是,进程之间的资源都是独立的,所以当有客户端(如:Client1)建立请求的时候,main process(主进程)的IO复用会监听到ListenFd的可读事件,如果在线程模型中,可以直接Accept将链接创建,并且将新创建的ConnFd交给线程中的某个线程中的IO复用机制来监控,因为线程与线程中资源是共享的。但是在多进程中则不能这么做。Main Process如果进行Accept得到的ConnFd并不能传递给子进程,因为他们都有各自的文件描述符序列。所以在多进程版本,主进程listenFd触发读事件,应该由主进程发送信号告知子进程目前有新的链接可以建立,最终应该又某个子进程来进行Accept完成链接建立过程,同时得到与客户端通信的套接字ConnFd。最终在用自己的多路IO复用机制来监听当前进程创建的ConnFd。

图1.30 网络并发模型五-进程池版本-2

如图1.30所示,进程版与与“模型五-单线程IO复用+多线程IO复用(链接线程池)”无大差异。

1)不同

  1. 进程和线程的内存布局不同导致,main process(主进程)不再进行Accept操作,而是将Accept过程分散到各个子进程``(``process``)中。

  2. 进程的特性,资源独立,所以main process如果Accept成功的fd,其他进程无法共享资源,所以需要各子进程自行Accept创建链接。

  3. main process只是监听ListenFd状态,一旦触发读事件(有新连接请求)。通过一些IPC(进程间通信:如信号、共享内存、管道)等, 让各自子进程Process竞争Accept完成链接建立,并各自监听。

2)优缺点

与五、单线程IO复用+多线程IO复用(链接线程池)无大差异。多进程内存资源空间占用稍微大一些,多进程模型安全稳定型较强,这也是因为各自进程互不干扰的特点导致。

7.模型六:单线程多路I/O复用+多线程I/O复用+多线程

本小节介绍一个更加复杂的模型六,我们在基于模型五上再加上一个多线程处理读写,服务端逻辑如下。

1)流程

  • Server在启动监听之前,开辟固定数量(N)的线程,用Thead Pool线程池管理,如图10.31所示。

图1.31 网络并发模型六-1

  • 主线程main thread创建listenFd之后,采用多路I/O复用机制(如:select、epoll)进行IO状态阻塞监控。有Client1客户端Connect请求,I/O复用机制检测到ListenFd触发读事件,则进行Accept建立连接,并将新生成的connFd1分发给Thread Pool中的某个线程进行监听,如图10.32所示。

图1=0.32 网络并发模型六-2

  • Thread Pool中的每个thread都启动多路I/O复用机制(select、epoll),用来监听main thread建立成功并且分发下来的socket套接字。一旦其中某个被监听的客户端套接字触发I/O读写事件,那么,会立刻开辟一个新线程来处理I/O读写业务,如图1.33所示。

图1.33 网络并发模型六-3

  • 但某个读写线程完成当前读写业务,如果当前套接字没有被关闭,那么将当前客户端套接字(如:ConnFd3)重新加回线程池的监控线程中,同时自身线程自我销毁。

以上是模型六的处理逻辑,我们来分析一下他的优缺点:

2)优点

在模型五、单线程IO复用+多线程IO复用(链接线程池)基础上,除了能够保证同时响应的最高并发数,又能解决读写并行通道局限的问题。同一时刻的读写并行通道,达到最大化极限,一个客户端可以对应一个单独执行流程处理读写业务,读写并行通道与客户端数量1:1关系,如图10.34所示。

图1.34 网络并发模型六-4

3)缺点

该模型过于理想化,因为要求CPU核心数量足够大。如果硬件CPU数量可数(目前的硬件情况),那么该模型将造成大量的CPU切换成本浪费。因为为了保证读写并行通道与客户端1:1的关系,那么Server需要开辟的Thread数量就与客户端一致,那么线程池中做多路I/O复用的监听线程池绑定CPU数量将变得毫无意义。如果每个临时的读写Thread都能够绑定一个单独的CPU,那么此模型将是最优模型。但是目前CPU的数量无法与客户端的数量达到一个量级,目前甚至差的不是几个量级的事。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值