TCP ソケットで奇妙なバグに遭遇しました。SO_KEEPALIVE
デフォルトですべてのソケットで有効になっているようです。
ソケットを作成してサーバーに接続するための短いテスト ケースを作成しました。接続直後、 でSO_KEEPALIVE
確認getsockopt
。値はゼロ以外で、MSDN によると、キープアライブが有効になっていることを意味します。多分私はこれを誤解しています。
最近、サーバーが 2 回連続で切断されるという奇妙なバグが発生しました。一部のクライアントは、ログオン情報を送信して応答を待っている状態でした。サーバーに接続されたソケットにオーバーラップが投稿されたにもかかわらずWSARecv
、サーバーがクラッシュしたことをクライアントに通知するための完了が投稿されなかったため、ソケットが完全に閉じられていないと想定しています。
約 2 時間後 (実際には約 1 時間 59 分 19 秒) に、読み取りの完了パケットが送信され、接続が開かれていないことがクライアントに通知されました。これが私が疑い始めたところSO_KEEPALIVE
です。
なぜこれが起こったのか理解しようとしています。何らかの理由で接続を失ったクライアントは自動的にサーバーに再接続するはずなので、少し問題が発生しました。この場合、切断が通知されなかったため、クライアントは 2 時間後まで再接続しませんでした。
明らかな解決策はタイムアウトを設定することですが、この状況がどのように発生するかを知りたいです。
SO_KEEPALIVE
アプリケーションサーバーまたはクライアントによってソケットに設定されていません。
// Error checking is removed for this snippet, but all winsock calls succeed.
int main() {
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
SOCKET foo = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
DWORD optval;
int optlen = sizeof(optval);
int test = 0;
test = getsockopt(foo, SOL_SOCKET, SO_KEEPALIVE, (char*)&optval, &optlen);
std::cout << "Returned " << optval << std::endl;
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
clientService.sin_port = htons(446);
connect(foo, (SOCKADDR*) &clientService, sizeof(clientService));
test = getsockopt(foo, SOL_SOCKET, SO_KEEPALIVE, (char*)&optval, &optlen);
std::cout << "Returned " << optval << std::endl;
std::cin.get();
return 0;
}
// Example output:
// Returned 2883584
// Returned 2883584