4.1 单线程 / 进程
在 TCP 通信过程中,服务器端启动之后可以同时和多个客户端建立连接,并进行网络通信
在单线程 / 单进程场景下,服务器是无法处理多连接的,解决方案也有很多,常用的有三种:
使用多线程实现 使用多进程实现 使用 IO 多路转接(复用)实现 使用 IO 多路转接 + 多线程实现
4.2 多进程并发
如果要编写多进程版的并发服务器程序,首先要考虑,创建出的多个进程都是什么角色,这样就可以在程序中对号入座了。在 Tcp 服务器端一共有两个角色,分别是:监听和通信,监听是一个持续的动作,如果有新连接就建立连接,如果没有新连接就阻塞。关于通信是需要和多个客户端同时进行的,因此需要多个进程,这样才能达到互不影响的效果。进程也有两大类:父进程和子进程,通过分析我们可以这样分配进程:
-
父进程:
-
负责监听,处理客户端的连接请求,也就是在父进程中循环调用 accept() 函数
-
创建子进程:建立一个新的连接,就创建一个新的子进程,让这个子进程和对应的客户端通信
-
回收子进程资源:子进程退出回收其内核 PCB 资源,防止出现僵尸进程
-
-
子进程:负责通信,基于父进程建立新连接之后得到的文件描述符,和对应的客户端完成数据的接收和发送。
-
发送数据:send() / write()
-
接收数据:recv() / read()
-
在多进程版的服务器端程序中,多个进程是有血缘关系,对应有血缘关系的进程来说,还需要想明白他们有哪些资源是可以被继承的,哪些资源是独占的,以及一些其他细节:
-
子进程是父进程的拷贝,在子进程的内核区 PCB 中,文件描述符也是可以被拷贝的,因此在父进程可以使用的文件描述符在子进程中也有一份,并且可以使用它们做和父进程一样的事情。
-
父子进程有用各自的独立的虚拟地址空间,因此所有的资源都是独占的
-
为了节省系统资源,对于只有在父进程才能用到的资源,可以在子进程中将其释放掉,父进程亦如此。
-
由于需要在父进程中做 accept() 操作,并且要释放子进程资源,如果想要更高效一下可以使用信号的方式处理

4.3 多线程并发
编写多线程版的并发服务器程序和多进程思路差不多,考虑明白了对号入座即可。多线程中的线程有两大类:主线程(父线程)和子线程,他们分别要在服务器端处理监听和通信流程。根据多进程的处理思路,就可以这样设计了:
-
主线程:
-
负责监听,处理客户端的连接请求,也就是在父进程中循环调用 accept() 函数
-
创建子线程:建立一个新的连接,就创建一个新的子进程,让这个子进程和对应的客户端通信
-
回收子线程资源:由于回收需要调用阻塞函数,这样就会影响 accept(),直接做线程分离即可。
-
-
子线程:负责通信,基于主线程建立新连接之后得到的文件描述符,和对应的客户端完成数据的接收和发送。
-
发送数据:send() / write()
-
接收数据:recv() / read()
-
在多线程版的服务器端程序中,多个线程共用同一个地址空间,有些数据是共享的,有些数据的独占的,下面来分析一些其中的一些细节:
-
同一地址空间中的多个线程的栈空间是独占的
-
多个线程共享全局数据区,堆区,以及内核区的文件描述符等资源,因此需要注意数据覆盖问题,并且在多个线程访问共享资源的时候,还需要进行线程同步。
本文围绕服务器并发展开,介绍了 TCP 通信中服务器与多客户端连接的情况。单线程/单进程场景下服务器无法处理多连接,有多种解决方案。还分别阐述了多进程并发和多线程并发服务器程序的设计,包括进程和线程的角色分配、资源使用及处理细节等。
658

被折叠的 条评论
为什么被折叠?



