本文主要是介绍没有任何关闭socket的日志,客户端和服务端进程都在, 网络连接完好, 为什么进行某操作后好好的tcp连接莫名其妙地断了呢?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
说明:本文只针对某个特定问题进行分析,定位出的最终结果不具有通用性, 但定位过程是可以揣摩揣摩的。
遇到这样一个问题:没有任何关闭socket的日志,客户端和服务端进程都在, 网络连接完好, 为什么进行某操作后好好的tcp连接莫名其妙地断了呢? 而且这个问题必现。
首先, 看日志, 没有close socket的任何日志, 而且, 可以确定的是, 如果代码有close socket的操作, 必定有日志输出。
其次, 查看客户端和服务端进程, 发现进程都在, 进程开看起来安然无恙。
最后, 经认真检查网络, 确认网络没有问题。
那为什么好好的tcp连接说断就断了呢? 别多想, 抓包是唯一证据。 结果发现, 服务端主动断开了连接, 这就奇怪了, 服务端明明没有去close socket啊。 进一步发现, 服务端进程的进程号非常大, 于是猜想是不是服务端挂掉后又被拉起来了? 经简单确认, 果然如此。 从tcp连接好到坏的过程中, 服务端进程的进程号改变了,说明服务端进程死了又生。原来如此! 而且, 从日志中看, 确实有系统级的日志显示: 该进程挂了, 该进程又重新被拉起来了。
我在Windows上来简单模拟一下这个场景。 服务端代码(服务端ip为192.168.1.102):
#include <stdio.h>
#include <winsock2.h> // winsock接口
#pragma comment(lib, "ws2_32.lib") // winsock实现int main()
{WORD wVersionRequested; // 双字节,winsock库的版本WSADATA wsaData; // winsock库版本的相关信息wVersionRequested = MAKEWORD(1, 1); // 0x0101 即:257// 加载winsock库并确定winsock版本,系统会把数据填入wsaData中WSAStartup( wVersionRequested, &wsaData );// AF_INET 表示采用TCP/IP协议族// SOCK_STREAM 表示采用TCP协议// 0是通常的默认情况unsigned int sockSrv = socket(AF_INET, SOCK_STREAM, 0);SOCKADDR_IN addrSrv;addrSrv.sin_family = AF_INET; // TCP/IP协议族addrSrv.sin_addr.S_un.S_addr = inet_addr("0.0.0.0"); // socket对应的IP地址addrSrv.sin_port = htons(8888); // socket对应的端口// 将socket绑定到某个IP和端口(IP标识主机,端口标识通信进程)bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));// 将socket设置为监听模式,5表示等待连接队列的最大长度listen(sockSrv, 5);SOCKADDR_IN addrClient;int len = sizeof(SOCKADDR);// sockSrv为监听状态下的socket// &addrClient是缓冲区地址,保存了客户端的IP和端口等信息// len是包含地址信息的长度// 如果客户端没有启动,那么程序一直停留在该函数处unsigned int sockConn = accept(sockSrv, (SOCKADDR*)&addrClient, &len);while(1){getchar();}closesocket(sockConn);closesocket(sockSrv);WSACleanup();return 0;
}
启动服务端。
客户端代码为(客户端ip为192.168.1.101):
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")int main()
{WORD wVersionRequested;WSADATA wsaData;wVersionRequested = MAKEWORD(1, 1);WSAStartup( wVersionRequested, &wsaData );SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = inet_addr("192.168.1.102");addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(8888);connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));while(1){getchar();}closesocket(sockClient);WSACleanup();return 0;
}
在客户端所在的电脑(也就是我现在写博客的电脑)上, 启动Wireshark抓包, 然后启动上述客户端。 这样就建立了tcp连接。
然后, 我们关掉服务端, 也就是关掉那个黑色的框框。 抓包结果如下:
抓包结果说明了一切。 跟网络相关的问题, 抓包是非常有说服力的。
至于为什么服务端进程死而复生, 这不属于本文要讨论的问题(我还是说一下原因吧:是别的模块错发了信号,误杀了该服务端的进程, 然后系统又重新拉起了它)。 通过本文, 我只想说, bug的原因可能有很多种, 下结论时, 不要武断, 要避免教科书式的僵化、死板思维, 要灵活。 不要轻信任何人的“大概”、“也许”,“应该”式的描述, 要大胆假设, 小心求证。
据我所知, 有很多公司, 搞bug要占据一半以上的时间, 有的部门, 甚至占到了80%以上, 有的更甚, 惨不忍睹。在这种情况下, 死板者死, 灵活者生。 有的bug开始看起来很难, 定位出原因后, 常常会让人哭笑不得, 有时候, 甚至容易笑掉大牙 。
OK, 先说这么多。
这篇关于没有任何关闭socket的日志,客户端和服务端进程都在, 网络连接完好, 为什么进行某操作后好好的tcp连接莫名其妙地断了呢?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!