C++ Socket服务端无法向客户端发消息 send()返回-1问题求助
问题排查结论
根因
核心故障是服务端套接字变量定义/拼写错误:
服务端main函数开头声明了两个套接字变量:SOCKET serverSocket, acceptSocket = INVALID_SOCKET;,但调用accept()接收客户端连接时,错误地在代码行前加了SOCKET关键字,还把变量名拼错成accpSocket,相当于在当前作用域重新定义了一个全新的局部变量接收已连接套接字:
// 错误写法:重新定义了accpSocket变量,和开头声明的acceptSocket不是同一个 SOCKET accpSocket = accept(serverSocket, NULL, NULL);
后续收客户端消息的recv()调用传入的是这个有效、已连接的accpSocket,所以收消息正常;但发消息的send()调用传入的是开头声明、从未被赋值、始终为INVALID_SOCKET的acceptSocket,对无效套接字调用send必然返回-1报错。
除此之外代码还有几个会导致异常的隐患:
- 头文件冲突:同时引入了
WinSock2.h和旧版winsock.h,两个头文件的宏、结构体定义存在冲突,可能引发未知编译或运行错误。 - 收发数据逻辑不严谨:
send()固定传2000字节长度,会把缓冲区里未初始化的垃圾数据一并发送,应该传用户实际输入的字符串长度(含结束符)。recv()不会自动在接收缓冲区末尾补字符串结束符\0,直接当C风格字符串输出会出现乱码、内存越界读取问题,需要手动在接收字节的末尾位置补结束符,且要先判断recv返回值是否有效再处理数据。
- 资源未释放:套接字使用完没有调用
closesocket()关闭,程序退出前没有执行WSACleanup(),会造成系统资源泄漏。 - 客户端代码也存在同样的收发长度、未补结束符的问题。
修复步骤
- 删除服务端头文件里的
#include<winsock.h>,解决头文件冲突。 - 修正accept处的变量定义,去掉多余的
SOCKET关键字,统一变量名,不要拼写错误,保证和开头声明的acceptSocket是同一个变量:// 正确写法:给开头声明的acceptSocket赋值,不重新定义变量 acceptSocket = accept(serverSocket, NULL, NULL); if (acceptSocket == INVALID_SOCKET) { cout << "Accepting failed! " << WSAGetLastError(); WSACleanup(); return -1; } else cout << "Accept connection!\n"; - 修正服务端recv逻辑,增加返回值判断,手动补字符串结束符:
int byterecv = recv(acceptSocket, recvMess, sizeof(recvMess)-1, 0); // 留1字节存结束符 if (byterecv <= 0) { cout << "Recv client data failed" << endl; } else { recvMess[byterecv] = '\0'; cout << "Client: " << recvMess << endl; } - 修正服务端send逻辑,传入实际发送长度:
cin.getline(sendMess, 2000); int sendLen = strlen(sendMess) + 1; // 包含字符串结束符 int bytesend = send(acceptSocket, sendMess, sendLen, 0); if (bytesend <= 0) cout << "Send failed, error code: " << WSAGetLastError() << endl; - 程序退出前增加资源释放逻辑:
closesocket(acceptSocket); closesocket(serverSocket); WSACleanup(); - 客户端代码对应修正recv、send的长度处理,手动补结束符,退出前关闭套接字、执行WSACleanup即可。
内容的提问来源于stack exchange,提问作者PreHemster
相关产品推荐
相关产品推荐

