2014-04-29 35 views
1

我目前正在爲SNMP打印機監視軟件開發自動發現功能。我需要一個幫助器方法,該方法從多個線程執行,每個線程都檢查一個範圍內的IP,以確定某個IP地址上的設備是否響應端口9100,確定它實際上是打印機,然後再發送SNMP請求。檢查IP地址和端口是否響應

我已經結束了以下方法,但是im沒有意識到這是否是正確的方法,並且如果按照約定在這種情況下正確使用Close()方法(我可以看到Dispose(), Disconnect()和Shutdown()方法也可用,所以可以使用?)。此外,我需要設置最大超時值。 5秒鐘,所以在展示結果之前線程不會停留太久。到目前爲止我的代碼:

private bool GetTCPPrinterResponse(IPAddress _ip) 
{ 
     int port = 9100; 

     bool isResponsive = false; 

     Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

     try 
     { 
      s.Connect(_ip, port); 

      isResponsive = true; 
     } 
     catch (SocketException) 
     { 
      isResponsive = false; 
     } 
     finally 
     { 
      s.Close(); 
     } 

     return isResponsive; 
    } 

方法編輯後:

private bool GetTCPPrinterResponse(IPAddress _ip) 
     { 
      int port = 9100; 

      bool isResponsive = false; 

      using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) 
      { 
       s.ReceiveTimeout = 3000; 
       s.SendTimeout = 3000; 

       try 
       { 
        s.Connect(_ip, port); 

        isResponsive = true; 
       } 
       catch (SocketException) 
       { 
        isResponsive = false; 
       } 
      } 

      return isResponsive; 
     } 

超時屬性的設置,沒有任何效果。

回答

1

這是檢查計算機/打印機在特定端口上的某個IP上是否聯機的正確方法。 您應該調用dispose方法來釋放對象正在使用的內存。 套接字類實現了IDisposable,所以最好是如果你使用using而不用擔心調用dispose,因爲using是爲你做的。

using(Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) 
{ 
//... 
} 

套接字類具有屬性ReceiveTimeout和SendTimeout。

+0

'Dispose'不會釋放被對象使用的內存。 Dispose用於釋放*非託管*資源。好的,在這種情況下,可能會包含一些非託管內存緩衝區,但它肯定不包含對象使用的內存。如果有必要,該內存將在未來的某個時間點由GC發佈。 –

+0

謝謝您的貢獻。我重寫了方法,利用IDisposable的Socket類實現,並添加了超時值。但是,後者似乎沒有效果。該方法返回的結果似乎是15秒後(我懷疑這是默認的超時值)。 – MartinChristensen

1

沒有必要爲此使用多線程。你正在綁定的線程將最終等待I/O操作完成。相反,爲什麼不使用異步I/O?

public async Task<Tuple<IPAddress, bool>> GetResponse(IPAddress address) 
{ 
    using (var client = new TcpClient(AddressFamily.InterNetwork)) 
    { 
    var connectTask = client.ConnectAsync(address, 80); 

    await Task.WhenAny(connectTask, Task.Delay(5000)); 

    if (connectTask.IsCompleted) 
     return Tuple.Create(address, true); 
    else 
     return Tuple.Create(address, false); 
    } 
} 

這可以進一步改善 - 超時機制是有點浪費(Task.Delay使用定時器是沒有必要的),但它很容易寫,理解和使用,並且它不浪費不必要的線程。然後

召喚就會是這樣的:

Task<Tuple<IPAddress, bool>>[] tasks = 
    new [] 
    { 
     GetResponse(Dns.GetHostAddresses("www.google.com").First()), 
     GetResponse(Dns.GetHostAddresses("www.microsoft.com").First()), 
     GetResponse(Dns.GetHostAddresses("www.yahoo.com").First()), 
     GetResponse(Dns.GetHostAddresses("www.altavista.com").First()), 
    }; 

Task.WhenAll(tasks).Wait(); 

foreach (var t in tasks) 
    t.Result.Dump(); // t.Result has the IP address and status 

這將等待所有設備的響應(或超時)。當然,沒有什麼能夠阻止你以更具交互性的方式做到這一點 - 你可以在數據返回時輕鬆更新UI。