2012-07-23 71 views
3

對於System.Net.WebRequest和System.Net.HttpRequest而言,在兼容多線程和套接字使用方面遇到了麻煩。我試圖走低一級,滾動我自己的污垢簡單的Http類。如何重新使用TCP客戶端?

由於之前的問題是每個線程太快創建太多的套接字,我試圖在多次迭代(for循環)上使用一個套接字(每個線程1個)。

代碼:

我的測試類(已硬編碼IP和端口,直到我能得到它的工作):

public sealed class Foo : IDisposable { 

     private string m_ip = "localhost"; 
     private int m_port = 52395; 
     private TcpClient m_tcpClient; 


     public Foo() { 
      m_tcpClient = new TcpClient(m_ip, m_port); 
     } 

     public void Execute() { 
      using(var stream = m_tcpClient.GetStream()) 
      using(var writer = new StreamWriter(stream)) 
      using(var reader = new StreamReader(stream)) { 
       writer.AutoFlush = true; 
       // Send request headers 
       writer.WriteLine("GET /File HTTP/1.1"); 
       writer.WriteLine("Host: " + m_ip + ":" + m_port.ToString()); 
       writer.WriteLine("Connection: Keep-Alive"); 
       writer.WriteLine(); 
       writer.WriteLine(); 

       // Read the response from server 
       string response = reader.ReadToEnd(); 
       Console.WriteLine(response); 
      } 
     }  

     void IDisposable.Dispose() { 
      m_tcpClient.Client.Dispose(); 
     } 
    } 

靜態無效的主要:

using(Foo foo = new Foo()) { 
    for(int i = 0; i < 10; i++) { 
     foo.Execute(); 
    } 
} 

錯誤

在for循環的第一次迭代成功完成後,我收到的錯誤爲The operation is not allowed on non-connected sockets.

我瞭解錯誤的原因,(在響應被讀取後TcpClient.Client關閉),但我不知道如何明確地告訴套接字保持打開狀態。

編輯 HTTP響應的進一步檢查我從它在它Connection: Close回服務器。我假設,因爲這是原始的TCP它不會解析HTTP。這可能是問題的根源嗎? (如果是的話,有沒有辦法忽略它)

回答

2

改變你主要方法的順序,所以您將創建一個新的對象每次迭代

for(int i = 0; i < 10; i++) 
{ 
    using(Foo foo = new Foo()) 
    { 
     foo.Execute(); 
    } 
} 

如果你要保持你的套接字打開,你需要重構你的應用程序一點點,所以它不會一個迭代後打電話Dispose,例如

public sealed class Foo : IDisposable {  
    private string m_ip = "localhost"; 
    private int m_port = 52395; 
    private TcpClient m_tcpClient; 

    private Stream stream; 
    private StreamWriter writer; 
    private StreamReader reader; 

    public void Execute() {   
     // Send request headers 
      ...  
     // Read the response from server     
    } 

    void Open(){ 
     m_tcpClient = new TcpClient(m_ip, m_port); 
     stream = m_tcpClient.GetStream(); 
     writer = new StreamWriter(stream); 
     reader = new StreamReader(stream); 
    } 

    void Close() { 
     m_tcpClient.Client.Dispose(); 
     reader.Dispose(); 
     writer.Dispose(); 
     stream.Dispose(); 
    } 

    //Plus Dispose implementation 
} 

這裏是使用方法

using(Foo foo = new Foo()) { 
    foo.Open(); 
    for(int i = 0; i < 10; i++) { 
     foo.Execute(); 
    } 
    foo.Close(); 
} 
+0

我讀的問題,他不_n想要創建多個實例。 – 2012-07-23 17:40:48

+0

雖然這將在同步程序中起作用,但當我嘗試在多線程環境中使用它時,它不會幫助我使用套接字消耗。 (由操作系統清理的插槽與線程迭代不匹配,因此單個線程將創建多個插槽,從而快速佔用資源) – James 2012-07-23 17:41:45

+0

如果您要這麼做,Dispose'應該可能調用Close。喜歡這個。儘管如此,我沒有看到一個令人信服的理由,不會將'close'重命名爲'Dispose'。對稱與'打開',也許...但是'關閉'實際上只是處理,所以... – cHao 2012-07-23 17:49:40

0

我認爲您的KeepAlive實現工作不正確。當您關閉流時,您正在關閉底層套接字。將您的流創建移動到構造函數。

public Foo() 
{ 
    m_tcpClient = new TcpClient(m_ip, m_port); 
    m_tcpStream = m_tcpClient.GetStream(); 
} 

然後保持兩者的生命,直到整個對象被關閉:

void IDisposable.Dispose() 
    { 
     m_tcpStream.Close(); 
     m_tcpClient.Client.Dispose(); 
    } 
+0

這導致錯誤'流不可寫'System.IO異常,並且該根目錄是TcpClient仍然關閉 – James 2012-07-23 17:57:09

+0

我想知道是否它期望一系列特定的事件以使連接可​​讀寫?編輯:是否有你必須實現iDisposable的原因?爲什麼不嘗試刪除它,看看它是否更具可預測性? – 2012-07-23 19:25:55

0

當調用第一Executeusing關閉(處置)m_tcpClient。你不需要那些using s

using(var stream = m_tcpClient.GetStream())