C++跨平台Socket程序Linux下无流量连接超时原因排查
问题根因
核心错误是端口号未做网络字节序转换,直接导致实际连接的目标端口完全错误,匹配你遇到的所有现象:
- 代码里直接写
server_addr.sin_port = port;,但sockaddr_in结构的sin_port字段要求传入网络字节序(大端序)的端口值,你传入的是主机字节序的整数。以小端序x86机器、连接7777端口为例:7777的十六进制为0x1E61,小端存储时内存排布为0x61 0x1E,被网络序解析后实际目标端口为0x611E即24862,根本不是你预期的7777。 - 你用tcpdump过滤的是7777端口的流量,程序实际发的SYN包是发往24862端口的,自然抓不到任何包;如果24862端口没有服务监听、中间网络设备直接丢弃对应SYN包不回RST,系统就会持续重传SYN直到触发连接超时,和你看到的报错完全一致。
另外代码还有三个不影响当前问题但存在隐患的写法:
- 给
sin_addr.s_addr赋值时绕了两次字符串转换(inet_addr(inet_ntoa(*address))),属于无意义的冗余操作,有引入转换错误的风险 gethostbyname的错误码存在h_errno而非errno中,原代码错误打印逻辑不准- 未对
sockaddr_in结构体做清零初始化,可能有残留脏数据影响连接
修复方案
修改Linux分支的连接逻辑,核心是给端口加上htons()字节序转换,同时修正冗余逻辑、补全初始化:
#else struct hostent *server; struct sockaddr_in server_addr; // 清零结构体避免脏数据 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; // 核心修复:主机序端口转网络字节序 server_addr.sin_port = htons(port); /* 解析主机地址 */ server = gethostbyname(host); if (server == NULL) { // gethostbyname错误使用h_errno printf("Error : %s \nFailed to resolve %s:%d", hstrerror(h_errno), host, port); return -1; } // 直接拷贝解析到的IP地址,不需要走字符串转换 memcpy(&server_addr.sin_addr.s_addr, server->h_addr, server->h_length); printf("Resolved: [%s] ===> [%s]\n", host, inet_ntoa(server_addr.sin_addr)); int iResult = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); printf("Connect returned : %d\n",iResult); if (iResult < 0) { printf("Error: %s\nFailed to connect\n",strerror(errno)); return -1; } printf("Connected to [%s:%d]\n",host,port); return 0; #endif
验证方法
重新编译运行程序后:
- 再用
tcpdump -i eth0 -v port 7777抓包,就能看到发往10.0.0.100:7777的TCP SYN报文 - 只要服务端设备的防火墙没有拦截7777端口,即可正常和nc监听的服务建立连接
内容的提问来源于stack exchange,提问作者Weed Cookie
相关产品推荐
相关产品推荐

