You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下C++ TCP Socket无法响应外部连接,Linux运行正常求助

分析Windows下TCP服务器异常的问题

从你的描述和代码来看,UDP功能正常但TCP在Windows下无响应,结合Wireshark抓包结果(三次握手完成、请求已发送但无返回),我整理了几个关键问题点,你可以逐一排查:


1. 非阻塞模式的跨平台不一致设置

看你的Socket初始化代码,Windows下TCP套接字的非阻塞模式被注释掉了,但Linux下是正常启用的:

#ifdef _WIN32
unsigned long nonblocking = 1;
// if(ioctlsocket(mTcpSocket,FIONBIO, &nonblocking))
// std::cout << "Couldn't set TCP-Socket to nonblocking mode! (" << std::strerror(errno) << ")" << endl;
...
#else
int tcpFlags = fcntl(mTcpSocket, F_GETFL, 0);
if(fcntl(mTcpSocket, F_SETFL, tcpFlags | O_NONBLOCK))
...
#endif

这会导致Windows下TCP是阻塞模式,但你的tcpListen循环逻辑是按照非阻塞设计的(accept失败直接continue)。如果是阻塞模式,accept本身没问题,但后续的recv会一直阻塞等待数据——如果客户端发送的是空请求(0字节),recv会卡在那里,根本进不到send逻辑里。

建议:要么取消Windows下TCP非阻塞设置的注释,要么调整循环逻辑适配阻塞模式。

2. accept的socklen_t参数未重置

你在循环外初始化了size = sizeof(sockaddr),但accept的第三个参数是输入输出参数,调用后size会被修改为实际的地址长度。在Windows下,如果后续循环复用这个被修改的size,很可能导致accept调用失败(错误码WSAEINVAL),但你的错误处理里用了strerror(errno)——Windows的Socket错误不会设置errno,只会通过WSAGetLastError()返回,所以你根本看不到这个错误。

修复方法:把size的初始化移到while循环内部,每次调用accept前重置:

while(mTcpServerRunning) {
    socklen_t size = sizeof(sockaddr); // 移到循环内,每次重置
    int cSock = accept(mTcpSocket, (sockaddr*) &remoteHost, &size);
    // ... 后续逻辑
}

3. Windows下错误处理的兼容性问题

你在Windows下同时混用了strerror(errno)和WSAGetLastError(),但Windows的Socket错误不会更新errno,strerror(errno)会显示完全无关的错误信息,导致你无法定位真正的问题。

建议:在Windows平台下,统一用WSAGetLastError()获取错误码,比如可以替换错误打印逻辑:

#ifdef WIN32
cerr << "Couldn't bind port. WSA Error: " << WSAGetLastError() << endl;
#else
cerr << "Couldn't bind port. (" << std::strerror(errno) << " " << errno << ")" << endl;
#endif

4. 客户端套接字未关闭导致资源泄漏

处理完客户端请求后,你没有调用closesocket(cSock)(Windows下用这个,Linux用close()),会导致套接字资源泄漏。Windows下每个进程的套接字数量有限,积累到一定程度就无法处理新连接了。

修复:在处理完请求后(不管成功失败),关闭客户端套接字:

if(r > 0) {
    // ... 发送时间字符串、打印日志的逻辑
    closesocket(cSock);
} else {
    // 即使recv失败,也要关闭套接字
    closesocket(cSock);
}

5. 空请求的处理逻辑缺失

根据Wireshark,客户端发送的是空字符串(PSH, ACK),这时候recv会返回0(表示客户端关闭了发送端连接),但你的代码只有r > 0时才会发送时间字符串,所以这种情况不会返回任何数据。

如果你的需求是无论客户端发送什么(包括空请求)都返回时间字符串,可以调整逻辑:

r = recv(cSock, buf, sizeof(buf), 0);
// 只要不是错误,就发送时间字符串
if(r != SOCKET_ERROR) {
    time(&t);
    timeinfo = localtime(&t);
    timeMsg = asctime(timeinfo);
    r = send(cSock, (char*) timeMsg.c_str(), timeMsg.length(), 0);
    // ... 后续日志和关闭套接字
}

按照上面的点逐一排查,应该能解决Windows下TCP无响应的问题。

内容的提问来源于stack exchange,提问作者Ian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:58:11