服务器收到客户端的关闭信号,TCP客户、服务器(fork式)

本文详细阐述了TCP连接的建立与终止过程,包括客户端从FIN_WAIT_1到TIME_WAIT的状态转换,以及服务器从CLOSE_WAIT到LAST_ACK的响应。同时,讨论了子进程成为僵死状态的原因及如何通过wait和waitpid函数进行处理,强调了信号处理函数在进程管理中的作用,特别提到了异常情况如接受到RST、服务器进程终止和服务器主机崩溃时的网络交互行为。
摘要由CSDN通过智能技术生成

正常启动

tcpserver &

可使用netstat -a来观察,监听套接字的state应为LISTEN,在建立连接后可看到新的连接。

正常终止

客户端发出中断命令,进入了FIN_WAIT_1的状态(发完了FIN),接受到服务器的ACK变为FIN_WAIT_2,接受到服务器的FIN并发送ACK后变为TIME_WAIT,在等待2MSL后正式关闭。

注意:

如果在FIN_WAIT_1状态时收到了FIN(服务器要求关闭),则发送ACK并进入CLOSING状态,收到服务器的ACK进入TIME_WAIT状态。

如果在FIN_WAIT_1状态接受到了FIN和ACK(服务器响应关闭并要求关闭),则发送ACK直接进入TIME_WAIT状态。

服务器收到客户端的FIN后,发送ACK并变为CLOSE_WAIT状态,之后服务器也发送FIN,变为LAST_ACK状态,接受到客户端的ACK后正式关闭。

子进程

在子进程退出后会发送SIGCHLD信号,但是父进程默认是不处理的,子进程则进入了僵死状态,资源没有被回收。如果一个进程挂掉,它的所有子进程都变为僵死,交给它的父进程来处理。处理方法:调用wait函数,可设置一个信号处理函数。当一个子进程终止,会发送该信号给父进程,执行绑定的信号处理函数。如果父进程在被中断时正阻塞于一个系统调用(如accept),那么accept会返回一个EINTER错误,父进程应该处理这个值。(可以设置SA_RESTART标志来自动重启被中断的系统调用)

信号

一旦安装了信号处理函数就一直安装着。

在处理该信号时,该信号是被阻塞的(即不能再次引发该信号),同时可设置sa_mask,在其中指定的信号也会阻塞。

如果信号在被阻塞时产生了多次,但是在解阻塞后只会再引发一次。

信号处理函数

void handler(int signo);

signal

void (*signal(int signo, void (*func)(int))) (int);

typedef void Sigfunc(int);

Sigfunc signal(int signo, Sigfunc *func);

正确处理僵死子进程

如果是在信号处理函数中调用wait,一次只能清理一个子进程,但是可能会有多个子进程同时死亡,这样就无法处理了(因为在信号处理函数运行时,引发多次该信号只会记为一次)。应该在信号处理函数中使用waitpid及WNOHANG选项。

while((pid = waitpid(-1, &stat, WNOHANG)) >0)

// 处理子进程

特殊情况

accept返回前连接终止

也就是在三次握手完成后,客户端却发送了RST。这种情况操作系统不同则有差异,在内核中处理、服务器进程更不看不到,或者返回EPROTO或ECONNABORTED。

服务器进程终止

例如kill掉服务器进程,这样会给客户端发送一个FIN,这样对于客户端来说服务器只是不再发送数据而已,如果客户端调用write,服务器会响应一个RST,如果客户端调用read,会返回EOF。

如果调用两次write

如果说无视RST,仍然写入,会导致内核向进程发送一个SIGPIPE信号,该信号的默认行为是终止进程。

服务器主机崩溃

当客户端调用read会阻塞并最终获得ETIMEOUT或EHOSTUNREACH或ENETUNREACH。

服务器主机崩溃后重启

由于丢失了之前所有的链接信息,服务器会响应RST(客户端收到ECONNRESET)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值