我正在使用VC ++ 2013社区在Windows 10专业版上使用某些协议,基本上包括三个步骤:
我发送标头,并在阻塞模式下调用recv()以通过TCP流从服务器接收数据。但是,recv()阻止,永远不会返回。
我使用WireShark来"关注" TCP流,它显示服务器确实继续发送二进制数据,我确实看到来自客户端的ACK消息,以确认它收到的每个段。但是,recv()仍会阻塞,永远不会返回。
我试图使用:
他们都不能收到任何数据。但是,WireShark仍然可以告诉服务器继续发送二进制数据。
我试图关闭防火墙,但问题仍然存在。
最奇怪的是,我的第一个实现实际上是在两天前成功从recv()获取数据。在那一天,recv()返回三次,然后再次被阻止。第二天,相同的实现,recv()永远不能返回任何东西。
我真的很困惑。谢谢!
以下是阻止Winsock版本的代码:
WSADATA wsaData;
int iResult;
SOCKET ConnectSocket = INVALID_SOCKET;
struct sockaddr_in clientService;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
//----------------------
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
//----------------------
// Create a SOCKET for connecting to server
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port of the server to be connected to.
clientService.sin_family = AF_INET;
auto ip = gethostbyname(name);
clientService.sin_addr = *(reinterpret_cast<struct in_addr *>(ip->h_addr));
clientService.sin_port = htons(DEFAULT_PORT);
//----------------------
// Connect to server.
iResult = connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService));
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
printf("Unable to connect to server: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Send an initial buffer
iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
printf("Bytes Sent: %ld\n", iResult);
// shutdown the connection since no more data will be sent
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iResult > 0)
printf("Bytes received: %d\n", iResult);
else if (iResult == 0)
printf("Connection closed\n");
else
printf("recv failed: %d\n", WSAGetLastError());
} while (iResult > 0);
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return 0;
答案 0 :(得分:0)
由于关机代码是来自微软页面(https://msdn.microsoft.com/en-us/library/windows/desktop/ms740121(v=vs.85).aspx)的复制/粘贴 - 我想这就是他们指示发送已完成的方式。我相信这解释了您所遇到的问题(来自上页):
注意当发出阻塞的Winsock调用(例如recv)时,Winsock可能需要等待网络事件才能完成调用。在这种情况下,Winsock会执行可警告的等待,这可以通过在同一线程上安排的异步过程调用(APC)来中断。在APC内发出另一个阻塞Winsock调用,该调用在同一个线程上中断正在进行的阻塞Winsock调用将导致未定义的行为,并且永远不会被Winsock客户端尝试。
我实际上刚刚意识到我只使用过非阻塞套接字并且总是在自己的线程上拥有接收代码。所以尝试添加这个: iResult = ioctlsocket(m_socket,FIONBIO,&amp; iMode);
从这里: https://msdn.microsoft.com/en-us/library/windows/desktop/ms738573(v=vs.85).aspx
注意:您将主要尝试从套接字接收数据的一系列失败尝试 - 因此您需要处理这些并且您也不希望紧密循环。