2011-06-01 146 views
16

我正在開發C++中的RTSP源代碼過濾器,並且使用WINSOCK 2.0 - 阻塞套接字。WINSOCK - 在不存在的IP上設置連接嘗試超時?

當我創建一個阻塞套接字,我設置其SO_RCVTIMEO至3秒,像這樣:

int ReceiveTimeout = 3000; 
int e = setsockopt(Socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&ReceiveTimeout, sizeof(int)); 

我的過濾器試圖連接到IP_ADDRESS:554(554 RTSP服務器端口)。如果有一個服務器偵聽的端口554上IP,一切順利,但是:

  1. 如果我的過濾器創建一個套接字到現有IP地址,但一個隨機端口上沒人聽connect()等待3秒鐘並返回WSAETIMEDOUT。所以3秒後,我知道提供的URL是不好的。

  2. 如果我的過濾器創建一個套接字到不存在的IP地址,並嘗試連接,它返回SOCKET_ERROR前掛機約10秒。因此,如果IP不存在網絡上SO_RCVTIMEO被忽略......

問題: 如何設置超時爲不存在的IP,在第二種情況下?我是否需要首先發送ICMP PING來查看IP是否存在,或者執行其他類似的檢查?

任何幫助將不勝感激。 Thanx。 :)

我的問題的答案

因爲我使用的是阻塞插座,來電connect()塊,直到建立連接,或者因爲主機沒有響應連接失敗,或者被拒絕連接。如果我將套接字的超時設置爲3秒,並嘗試連接到一個不存在的主機,我的電腦(客戶端)將發送帶有SYN標誌的TCP數據包,啓動三通握手。通常情況下,主機如果啓用,將使用包含ACKSYN標誌集的TCP數據包進行響應,然後客戶機(我)將發送標記爲ACK的TCP數據包。然後建立連接。但是如果主機關閉,並且發送了SYN,則客戶端會等到3秒超時過期,然後再次嘗試重新嘗試,直到達到TcpMaxConnectRetransmissionsMICROSOFT ARTICLE)註冊表設置爲止,因爲主機可以處於UP狀態,但是SYN數據包可能會丟失...我的Windows XP的設置爲4,我猜,所以每次嘗試發送SYN時,它會等待3秒,當第四次嘗試失敗時,它會返回SOCKET_ERROR(12秒後),並且將WSAETIMEDOUT設置爲最後一次WSA錯誤。

解決方法是使用非阻塞套接字,並嘗試手動測量連接嘗試時間(因爲現在connect()不會像Martin James所建議的那樣)。

另一種方法是使用註冊表,這是不得已而爲之撥弄......

+0

這是在Windows或控制檯應用程序?這個問題很重要,因爲它讓我知道你可以使用的wsapi中的哪些工具。 – johnathon 2011-06-01 12:23:47

+0

它是一個DirectShow推送源過濾器,DLL庫。 – Cipi 2011-06-01 12:29:28

回答

2

勉爲其難。遠程IP可能沒有運行PING服務器,或者PING可能被某個路由器阻塞,所以沒有任何幫助。你能不能等待10秒,然後做出你使用的任何錯誤指示?

如果您絕對必須在3秒後超時嘗試連接,您可以自行計時。

+2

我得到了ping,但我怎麼能自己計算出來呢?當它仍在嘗試連接時,如何阻止來自另一個線程的套接字連接嘗試?我需要'connect()'函數來返回,以便我可以有一個可拆卸的插座。或者我錯了? – Cipi 2011-06-01 10:18:07

2

事實上,伯克利套接字沒有超時連接,所以你不能設置它。 ICMP PING沒有什麼幫助,我不知道爲什麼,但是如果主機不存在,你會花1秒左右的時間與PING聯繫。嘗試使用ARP來檢測是否存在主機。

+0

其實,ARP並不是一種選擇,因爲服務器在廣域網上,而不是在局域網上,所以ARP不會工作......或者我錯了? – Cipi 2011-06-01 10:48:25

+0

[Wiki](http://en.wikipedia.org/wiki/Address_Resolution_Protocol)表示ARP存在於IEEE 802.11 – xandox 2011-06-01 11:26:30

+0

Ooook會嘗試它。 – Cipi 2011-06-01 11:39:32

0
從CMD可以ping IP,像這樣「平-w 100-N 1 192.168.1.1」

它將在100ms內

返回您可以通過「回聲檢查返回碼超時

%ERRORLEVEL%0 =正常,1 =失敗,那麼你知道你應該嘗試在C++連接

bool pingip_nowait(const char* ipaddr) 
{ 
    DWORD exitCode; 

    STARTUPINFO si; 
    PROCESS_INFORMATION pi; 

    ZeroMemory(&si, sizeof(si)); 
    si.cb = sizeof(si); 
    ZeroMemory(&pi, sizeof(pi)); 
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; 
    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); 
    si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 
    si.hStdError = GetStdHandle(STD_ERROR_HANDLE); 
    si.wShowWindow = SW_HIDE; 

    CString cmd = "ping -w 100 -n 1 "; 
    cmd += ipaddr; 
    if (!CreateProcess(NULL, 
     cmd.GetBuffer(), 
     NULL, 
     NULL, 
     FALSE, 
     0, 
     NULL, 
     NULL, 
     &si, 
     &pi)) { 
      TRACE("ERROR: Cannot launch child process\n"); 
      return false; 
    } 

    // Give the process time to execute and finish 
    WaitForSingleObject(pi.hProcess, 200L); 

    if (GetExitCodeProcess(pi.hProcess, &exitCode)) 
    { 
     TRACE("ping returned %d\n", exitCode); 
     // Close process and thread handles. 
     CloseHandle(pi.hProcess); 
     CloseHandle(pi.hThread); 
     return exitCode==0 ? true : false; 
    } 
    TRACE("GetExitCodeProcess() failed\n"); 
    CloseHandle(pi.hProcess); 
    CloseHandle(pi.hThread); 
    return false; 
}