c - Winsock:服务器上的 recv() 被阻塞,但客户端已经移过 send()
问题描述
我正在为学校做一个项目,并遇到了以下问题。尽管我的客户端已经发送了完整的消息,但我的服务器在 recv() 上被阻塞了。
这就是我想要发生的事情:
Server Client
recv() <---- send()
send() ----> recv()
这是正在发生的事情:
Server Client
recv() <---- send()
recv() ----- recv()
一些背景
2 周前,我使用已经编码的服务器应用程序自行创建了客户端。当我对客户端进行编码时,它与提供的服务器一起正常运行,所以我想说客户端是错误的,但我不知道如何让我编码的服务器识别不会有更多数据进入。
代码
这是我认为相关的代码:
客户:
bytesSent = 0;
retVal = send(sock, phrase, msgLen, 0);
bytesSent = retVal;
while (bytesSent < msgLen) {
retVal = send(sock, phrase + bytesSent, msgLen - bytesSent, 0);
if (retVal == SOCKET_ERROR) {
DisplayFatalErr("send() function failed.");
exit(1);
}
bytesSent += retVal;
// May need to re-call send in order to keep sending the data.
}
...
bytesRead = 0;
while (bytesRead < msgLen) {
retVal = recv(sock, rcvBuffer, RCVBUFSIZ - 1, 0);
if (retVal <= 0) {
DisplayFatalErr("recv() function failed.");
exit(1);
}
bytesRead += retVal;
for (int i = 0; i < retVal; i++) {
printf("%c", rcvBuffer[i]);
}
}
服务器:
char* rcvBuffer[RCVBUFSIZ]; // RCVBUFSIZ = 50
char* msg = "";
int bytesRead = 0;
do {
if ((bytesRead = recv(clientSock, rcvBuffer, RCVBUFSIZ - 1, 0)) == 0) {
break;
}
if (bytesRead < 0) {
return -1;
}
char* msgConcatenated;
int msgLen = strlen(msg);
msgConcatenated = malloc(msgLen + bytesRead);
if (msgConcatenated != NULL) {
int newMsgLen = strlen(msgConcatenated);
strncpy_s(msgConcatenated, newMsgLen, msg, msgLen);
strncat_s(msgConcatenated, newMsgLen, rcvBuffer, bytesRead);
msg = msgConcatenated;
}
} while (bytesRead != 0);
如果我需要提供额外信息,请告诉我。
解决方案
当使用TCP时,为了通知套接字的另一端不再发送数据,必须发送一个设置了 FIN 标志的数据包。这在 Winsock 中通过调用shutdown
带有 SD_SEND 作为第二个参数的函数来完成。这将导致套接字另一端的程序在调用时不再阻塞recv
。相反,recv
将返回 0 表示连接已正常关闭(除非还有尚未读取的数据)。有关详细信息,请参阅有关关机功能的 Microsoft 文档。该文档页面还包含一些有关优雅套接字关闭的有用信息。
此外,正如评论中所指出的,您的代码在以下行中包含内存泄漏:
msg = msgConcatenated
在该行中,您msg
无需先释放msg
指向的内存就重新分配。不幸的是,修复内存泄漏并不容易,因为您不能在重新分配它之前简单地调用free
它msg
。这是因为,在循环的第一次迭代中,msg
还可以指向动态分配的内存以外的其他内容。因此,要修复泄漏,您还必须跟踪所msg
指向的内存类型,或者使其始终指向动态分配的内存,即使字符串为空(即它仅包含终止空字符) .
推荐阅读
- python-3.x - 如何执行另一个 Python 脚本(服务器)但同时保持当前脚本运行
- gradle - 无法解析其他项目配置
- python - 用逗号替换每行中的多个空格
- java - JavaFXPlugin 编译错误(Java 版)
- python - 有没有办法打破两个while循环?
- php - 在 Laravel 5.8 中使用 Sweet Alert 2 删除确认
- sql - 计算两个日期之间的整年和部分月份
- swift - Firebase 'setValue' 函数重复并且不会停止 Swift
- python - TypeError:格式字符串的参数不足 - Python 格式化问题
- refactoring - 重构不使用流变量和流变量的模型库