在之前的套接字编程内容中,我们讲述完了UDP和TCP的主要内容,但是对于TCP通信中具体的实现还存在一些问题没有解决,所以我们本篇博客将对进行分析和解决。
目录
1.引入
2.多进程
3.多线程
1.引入
在上一篇博客中,当我们使用TCP通信时,发现客户端和服务端并不能很好的实现稳定通信,这是由于我们新建连接时,所设计接收它的“new_sock"是一个局部变量。故当一次通信结束后,局部变量的生命周期也随之结束,进而导致通信中断。
我们根据TCP协议的特性:新建连接时需要创建新的socket--设计的循环接收新连接。反而因为局部变量的生命周期导致通信无法稳定运行,那么为了处理因为使用局部变量来接收新建连接,而导致的通信不稳定问题。
我们可以使用多进程或多线程来进行处理,通过新建的子进程或线程来接收新建连接,并让新建的子进程或线程来和客户端通信。我们将执行流分开,在服务端创建新的执行流,来负责与每个新连接的客户端通信。如此操作,更好的满足了TCP通信的特性,并且实现了TCP通信的稳定性。
2.多进程
对于主进程我们只让其负责一件事情,即获取新连接。若获取新连接成功,则创建一个新的子进程,让新创建的子进程来和客户端进行通信。
而子进程能够和客户端通信是因为子进程复制父进程,会连同获取的新建连接描述符也也一起复制,所以子进程在内核中也能找到对应的socket结构。
我们编译并执行,可以得到结果如下,并发现在客户端退出后,查看服务端进程中并未存在僵尸进程。
从结果上来看,多客户端和服务端通信,服务端并无法很好的将发送方和回复方联系起来。这是因为从设计代码中我们并未将其一一分开,就是多个客户端会抢同一个进程来让服务端回复数据。
最后需要提醒的是,在设计代码中,存在两个关键点需要我们注意。首先是注意僵尸进程的产生,防止子进程在推出之后成为僵尸进程,占用资源;
其次是父进程中文件描述符的处理,因为父子进程之间“代码共享,数据独有”所导致的:父进程同样会创建套接字,但其实际上并不会使用,如此进行下去后,会导致父进程中套接字创建过多,造成资源泄露问题。
3.多线程
多线程处理思路和多进程类似,具体设计代码中根据线程和进程创建的异同来完成。
为了便于对线程的操作,我们对之前封装的tcp_sock.hpp类做一定改变:
加入fd和set函数,并将析构函数注释掉,具体原因在上述多线程代码中存在注释解释。
最后编译并实行得到结果如上所示,我们可以发现多线程处理仍可以很好的完成TCP协议通信。