最近、私のソフトウェアの数人のユーザーがWindows 8では機能しないと言ってきました。調査の結果、奇妙な理由で、サーバーソケットが常に接続を受け入れるとは限らないが、タイムアウトすることが判明しました。 。
さらに奇妙なことに、リモートホストに接続するときだけでなく、ローカルホストに接続するときにも発生します。
「何を試しましたか?」
- 明らかなこと:ファイアウォールをオフにして(効果なし)、他のソフトウェアが機能するかどうかを確認し(機能する)、コードのランダムな行を変更してみてください(効果なし)。
- あまり目立たないもの:クライアントまたはサーバーインスタンスごとに1つではなく、グローバルWSAStartupを使用します(効果はありません)。
注意:まったく同じコードがWindowsXPとWindows7で正常に機能し、ローカルホスト接続にも影響します(ハードウェアの問題ではありません)。また、接続の3分の1だけが失敗し、残りは正常に機能します。
さて、これらすべての単語よりもはるかに便利なので、実際のコードをいくつか紹介します。
ソケットのセットアップ:
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]Socketerror:10060」エラーを吐き出すので、その後に続くコードはまったく関係ありません。
select
実際のループは他のことも行うため、この呼び出しがありますが、ソケットに関連していないため、省略しました。
さらに見知らぬ人:Wiresharkによると、Windowsは実際のネットワークエラーを起こしているようです:http://i.imgur.com/BIrbD.png
私はしばらくの間これを理解しようとしてきました、そして私はおそらくただ愚かなことをしているだけなので、私はあなたのすべての答えに本当に感謝しています。