聊天服务器-防止意外退出

Posted by 周思进 on September 1, 2019

接着上一章节内容,在进行调试的时候,发现telnet客户端退出的情况下,服务端也退出了,但查看服务端代码处理逻辑中是不存在退出操作的。

通过tcpdump抓包显示telnet关闭时的数据交互包如下图所示:

RST

telnet客户端在发送了FIN包之后,服务端又进行了PSH操作(发送数据) ,telnet客户端紧接着发送了RST数据包。

而如果继续往收到RST数据包的套接字进行数据发送操作,则发送进程会收到SIGPIPE信号,该信号的默认操作是退出进程。

通过man 7 signal查看了解到,当对端已关闭了该连接的读方向,本端仍旧尝试往其发送数据(目前看网络套接字是收到RST包之后再尝试写),则系统会产生SIGPIPE信号,并默认退出进程。

实际通过代码添加打印,最终也明确是服务端程序在收到客户端的FIN包之后,又进行了2次写操作(当然再第二次写的时候,服务端进程退出了)。

对于服务端肯定不能因为这样的原因导致退出了,所以需要对SIGPIPE信号做忽略处理,在代码中增加如下语句

signal(SIGPIPE, SIG_IGN);

进行修改之后,测试没有崩溃了,同样抓了下交互包,但发现只有如下交互流程:

关闭

即只有客户端发起了关闭操作,服务端并没有发送FIN包

通过’netstat -anp | grep server’ 命令查看(我服务端执行文件名为server),显示端口状态如下:

端口状态

端口状态为CLOSE_WAIT,所以服务端的确没发起关闭操作(TCP状态机后面再单独整理输出),查看代码的确是忘记关闭套接字描述符了…

这种问题其实属于资源未释放了,任何资源(文件描述符、申请的动态内存)一定要谨记在不使用后进行释放操作!

修改之后进行抓包如下,可以看到正常的四次挥手(服务端的ACK和FIN一块发送了)。 正常关闭