我遇到了TCP套接字的一個奇怪的錯誤。看來默認情況下,所有套接字上都啓用了SO_KEEPALIVE
。Windows TCP套接字默認啓用SO_KEEPALIVE?
我寫了一個簡短的測試用例來創建套接字並連接到服務器。連接後立即檢查SO_KEEPALIVE
與getsockopt
。該值非零,根據MSDN,意味着保持活動狀態。也許我誤解了這一點。
我最近有一個奇怪的錯誤,連續兩次斷開服務器。有些客戶處於他們發送登錄信息並等待響應的狀態。即使有一個重疊的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
您是否在WSAIoctl()/ SIO_KEEPALIVE_VALS下獲得了相同的結果?我也會輸出「test」的值,在Unix中,存入optval的值往往是0和1,而不是0,並且是一個「非常隨機的結果」。 – CoreyStup 2011-02-07 16:29:46
我刪除了測試的輸出以保持代碼片段簡潔,值始終爲0.快速搜索,我沒有看到如何使用WSAIoctl檢索設置,只知道如何設置它們。這是一種垃圾值,因爲它每隔一段時間都會更改一次,但是MSDN文檔會聲明啓用了任何非零均值。 – 2011-02-07 16:35:10