多线程Socket编程:服务器无法接收客户端多条消息求助
问题分析与解决方案
首先,咱们来定位你遇到的问题:发送客户端在发送第一条消息后卡住,无法继续输入下一条,核心原因出在你的发送客户端代码里的recv调用上。
为什么会卡住?
看你的发送客户端代码,每次调用send发送消息后,立刻调用了recv等待服务器的响应:
int sendResult = send(sock, userInput.c_str(), userInput.size() + 1, 0); if (sendResult != SOCKET_ERROR) { ZeroMemory(buf, 4096); int bytesReceived = recv(sock, buf, 4096, 0); // 这里会阻塞! if (bytesReceived > 0) { std::cout << "SERVER> " << std::string(buf, 0, bytesReceived) << std::endl; } }
但你的服务器逻辑是把发送客户端的消息转发给固定的显示客户端,并没有给发送客户端回复任何内容。recv是阻塞式调用,它会一直等待服务器发送数据,而服务器永远不会发,所以你的客户端就卡在这一步,无法回到循环开头等待用户输入下一条消息。
而PuTTY作为客户端时,它不会主动去调用recv等待服务器回复(或者说你没触发这个行为),所以不会出现卡住的情况。
解决方案
根据你的需求,有两种修复方式:
方案1:移除发送客户端的recv调用(推荐,因为你不需要服务器给发送客户端回复)
既然你的服务器不需要给发送客户端返回数据,那直接删掉send之后的recv相关代码即可,这样发送完消息后程序会立刻回到循环,等待用户输入下一条。
修改后的发送客户端核心代码:
do { std::cout << "> "; std::getline(std::cin, userInput); if (userInput.size() > 0) { int sendResult = send(sock, userInput.c_str(), userInput.size() + 1, 0); if (sendResult == SOCKET_ERROR) { std::cerr << "Send failed, Err #" << WSAGetLastError() << std::endl; break; // 发送失败就退出循环 } // 移除这里的recv代码 } } while (userInput.size() > 0);
方案2:修改服务器,给发送客户端发送确认消息
如果你希望服务器给发送客户端返回一个“消息已收到”的确认,那需要完善服务器的转发逻辑,在把消息发给显示客户端后,给发送客户端回复一条确认信息。
比如服务器代码中处理客户端消息的部分(补充你未写完的逻辑):
else { char buf[4096]; ZeroMemory(buf, 4096); int bytesReceived = recv(sock, buf, 4096, 0); if (bytesReceived <= 0) { // 客户端断开连接 closesocket(sock); FD_CLR(sock, &master); } else { // 转发给显示客户端(假设你已经记录了显示客户端的socket) SOCKET displayClient = ...; // 替换为你实际的显示客户端socket变量 send(displayClient, buf, bytesReceived, 0); // 给发送客户端回复确认 std::string ackMsg = "Message received and forwarded\r\n"; send(sock, ackMsg.c_str(), ackMsg.size() + 1, 0); } }
这样发送客户端的recv就能收到服务器的确认,不会卡住,能继续输入下一条消息。
额外的小建议
- C++标准中
main函数应该返回int,而不是void,建议修改为int main(),最后加return 0;。 - 在服务器代码中,要记得处理客户端断开的情况(比如
recv返回0或错误时,从fd_set中移除该socket并关闭)。 - 显示客户端的代码中,
socket创建失败后没有调用WSACleanup就返回了,这是资源泄漏,建议补充:
if (sock == INVALID_SOCKET) { std::cerr << "Can't create socket, Err #" << WSAGetLastError() << std::endl; WSACleanup(); // 补充这句 return; }
内容的提问来源于stack exchange,提问作者Seren




