2016-07-31 37 views
2

爲什麼socket()沒有返回INVALID_SOCKET?我認爲它會失敗,然後我可以退出我的功能。我的函數的錯誤檢查一直持續到recvfrom(),然後在沒有互聯網連接時掛起。我以爲socket()sendto()會返回一個錯誤代碼,當我沒有互聯網連接,但他們不是。我試圖依靠他們的失敗作爲一個標誌,用戶沒有互聯網連接並退出我的功能,但這只是不工作的一些奇怪的原因。當沒有互聯網連接時,socket()和sendto()不返回錯誤代碼

void myFunc() 
{ 
    WSADATA wsaData; 
    WSAStartup(MAKEWORD(2, 2), &wsaData); 

    struct sockaddr_in server_addr; 
    memset(&server_addr, 0, sizeof(server_addr)); 
    server_addr.sin_family = AF_INET; 
    server_addr.sin_addr.s_addr = inet_addr("myipaddress"); 
    server_addr.sin_port = htons(123); 

    // Doesn't fail when there's no internet connection 
    protoent *proto = getprotobyname("udp"); 
    int s = socket(PF_INET, SOCK_DGRAM, proto->p_proto); 
    if (s == INVALID_SOCKET) { 
     goto Cleanup; 
    } 

    // Doesn't fail when there's no internet connection 
    char msg[48] = { 0x08, 0, 0, 0, 0, 0, 0, 0, 0 }; 
    int iResult = sendto(s, msg, sizeof(msg), 0, (struct sockaddr *) &server_addr, sizeof(server_addr)); 
    if (iResult == SOCKET_ERROR) { 
     goto Cleanup; 
    } 

    // Hangs when there's no internet connection 
    memset(msg, 0, sizeof(msg)); 
    struct sockaddr saddr; 
    socklen_t saddr_l = sizeof(saddr); 
    iResult = recvfrom(s, msg, 48, 0, &saddr, &saddr_l); 
    if (iResult == SOCKET_ERROR) { 
     goto Cleanup; 
    } 

Cleanup: 
    closesocket(s); 
    WSACleanup(); 
} 
+2

風格問題 - 您可以通過使用RAII技術來清除那些'goto Cleanup;'調用,其中清理將在函數返回時自動發生。 – PaulMcKenzie

+0

@PaulMcKenzie是的,但假設'myFunc()'的用戶會一直足夠體貼/記住在使用該函數後進行清理。 – Merl

+1

你會如何定義「沒有互聯網連接」?請注意,您使用的數據報套接字定義不可靠。 –

回答

2

因爲沒有要求將套接字連接到互聯網。許多應用程序在一臺機器上使用套接字進行進程間通信。沒有互聯網連接時,這些應用程序仍可以正常運行。

sendto()可以說可以返回一個錯誤代碼;它可以(在某些情況下,如桌面上有關網絡連接狀態的通知所示)知道該數據包永遠不會被傳送。然而,UDP通信和sendto()不保證交付任何,顯然你正在使用的實現不考慮缺乏連接值得錯誤代碼。可以說這是一個實施質量問題。

recvfrom()只要您爲消息指定(可能無限期地),但從未接收到消息就等待。再次,這是在規範範圍內,無論這種特定情況是否被標記,它都可以被認爲是實施質量問題。

+0

上使用定時等待機制(select,epoll,...)「它應該知道」究竟如何?你能提出一個機制嗎? –

+0

這不是很明顯嗎?一旦你指定了一個地址,就清楚它是否是本地機器上的地址。如果沒有網絡連接(可檢測到的情況;至少我的機器會立即告訴我是否拉網線),則無法傳送。 –

+0

(1)網絡電纜!=互聯網連接(2)沒有網絡電纜!=無法送達的數據包(我的頭頂上,你可以運行一個虛擬機,只有VM的定製內核模塊知道哪些數據包可交付給它)。 –

0

我看着Linux手冊頁的sendto(假設所有相關的實現是充分類似於Berkeley套接字基線)位置:

http://linux.die.net/man/2/sendto

的文件沒有提到如果報告和錯誤網絡堆棧'知道'該消息無法傳遞。這是合理的,因爲套接字的傳輸可能不是IP4或IP6。它可以是我們選擇編寫驅動程序的任何傳輸方式:數據包收音機,串行電纜或運載鴿子(如果我們能夠計算將打印的信息加載到其書包中的硬件)。

唯一參照從傳輸可能的錯誤是在這裏:

這些是由套接字層產生的一些標準誤差。可能會生成其他錯誤並從底層協議模塊返回; 參見他們各自的手冊頁

正如其他人所說的,UDP是一種不可靠的數據報協議。預計不可靠。預計未送達消息。因此不是真的是一個錯誤。協議層作者編寫代碼來處理傳輸錯誤的動機不大 - 因爲它們也是可以預期的,而不是在此協議的上下文中出現錯誤。

當通過TCP打開套接字時,套接字連續性缺失是一個錯誤。如果傳輸報告數據包傳輸不可能(足夠長時間),那麼這是協議中的錯誤條件。

相關問題