我的软件的一些用户最近来找我,告诉我它在 Windows 8 上不起作用。经过调查发现由于某种奇怪的原因,我的服务器套接字并不总是接受连接,而是让它们超时.
更奇怪的是:连接到本地主机时也会发生这种情况,而不仅仅是远程访问它时。
“你试过什么?”
- 显而易见的东西:关闭防火墙(无效),查看其他软件是否有效(有效),尝试修改随机代码行(无效)。
- 不太明显的东西:使用全局 WSAStartup 而不是每个客户端或服务器实例一个(无效)。
提醒:完全相同的代码在 Windows XP 和 Windows 7 上运行良好,它也会影响 localhost 连接(不是硬件问题)。此外,只有三分之一的连接失败,其余连接正常。
好的,现在是一些真正的代码,因为它比所有这些词更有用。
套接字设置:
int iResult;
struct addrinfo *result = NULL;
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// "Resolve" our localhost
iResult = getaddrinfo(NULL, port, &hints, &result);
if (iResult != 0) {
printf("error (2) : %d\n", iResult);
return false;
}
// Create the socket
listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (listenSocket == INVALID_SOCKET) {
freeaddrinfo(result);
printf("error (3) : %d\n", WSAGetLastError());
return false;
}
// Bind it
iResult = bind(listenSocket, result->ai_addr, result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
freeaddrinfo(result);
closesocket(listenSocket);
printf("error (4) : %d\n", WSAGetLastError());
return false;
}
freeaddrinfo(result);
// Listen
iResult = listen(listenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
closesocket(listenSocket);
printf("%d\n", WSAGetLastError());
return false;
}
正如您可能看到的,它几乎直接取自 MSDN,应该没问题。此外,它适用于 2/3 的连接,所以我真的怀疑是设置代码有问题。
接收方代码:
if (listenSocket == INVALID_SOCKET) return false;
#pragma warning(disable:4127)
fd_set fds;
SOCKET client;
do {
FD_ZERO(&fds);
FD_SET(listenSocket, &fds);
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
if (!select(1, &fds, NULL, NULL, &timeout)) continue; // See you next loop!
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
// Accept the socket
client = accept(listenSocket, (struct sockaddr *)&addr, &addrlen);
if (client == INVALID_SOCKET) {
printf("[HTTP] Invalid socket\n");
closesocket(listenSocket);
return false;
}
// Set a 1s timeout on recv()
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));
// Receive the request
char recvbuf[513];
int iResult;
std::stringbuf buf;
clock_t end = clock() + CLOCKS_PER_SEC; // 1s from now
do {
iResult = recv(client, recvbuf, 512, 0);
if (iResult > 0) {
buf.sputn(recvbuf, iResult);
} else if (iResult == 0) {
// Hmm...
} else {
printf("[HTTP] Socket error: %d\n", WSAGetLastError());
break;
}
} while (!requestComplete(&buf) && clock() < end);
这段代码吐出一个“[HTTP] Socket error: 10060”错误,所以它之后的任何代码都是相当不相关的。
调用在select
那里是因为实际的循环也做了一些其他的事情,但我把它省略了,因为它与套接字无关。
更奇怪的是:根据 Wireshark 的说法,Windows 似乎正在犯实际的网络错误:http: //i.imgur.com/BIrbD.png
我一直在努力解决这个问题,我可能只是在做一些愚蠢的事情,所以我非常感谢你的所有回答。