2012-09-28 54 views
5

我正在創建一個代理服務器,它監聽特定端口上的傳入連接。連接通常是Http請求(GET/POST)。不能決定是否應該選擇HttpListener或套接字。我將修改代理中的HttpRequests,然後將其轉發到最終目的地。Sockets vs HttpListener

什麼時候你更喜歡HttpListener而不是Sockets。每個的好處是什麼?

+0

解析/修改HTTP標頭,閱讀的內容,處理分塊傳輸等與HttpListener簡單得多。 –

+0

你打算對HttpRequests進行什麼樣的修改? –

+0

我將改變HostHeader,重定向一些請求等 – NewUnhandledException

回答

13
  • 的HttpListener
    • 優點允許使用HTTP.SYS其他進程端口共享(包括使用HttpListener或IIS那些,只要該前綴是唯一的)
    • Http.sys的使用I/O完成端口爲你;很難自己設置而不使用TcpListener
    • HttpListener解析HTTP標頭併爲響應創建HTTP標頭
    • 爲您提供了一組非常類似於ASP.Net中的標頭的類,本地主機客戶端通過HTTP發送大的有效載荷相比較,引起來進行這些有效載荷的數個附加拷貝的TcpListener或單聲道的HttpListen - 餅乾等
  • HttpListener
    • 主要的缺點呃在Windows上。如果需要每個CPU的最大吞吐量,則應避免在同一臺機器上的進程之間發送大型(例如超過5 MB)的POST主體。考慮使用內存映射文件(本質上是共享內存)。當客戶機和服務器位於不同的機器上時,這些額外的副本不成問題。
    • 不允許顯式控制TCP套接字保持打開狀態的時間; http.sys爲你管理這個(這通常不是一個巨大的缺點,但它只是要注意的東西)
    • 頭/ cookie類中的任何錯誤都會咬你;例如設置多個cookie會導致HttpListener返回一個包含多個cookie的Set-Cookie頭,這個IE會處理,但Chrome會完全忽略(您必須手動推送cookie並添加您自己的Set- Cookie頭的工作,解決這個問題)
  • 優勢的TcpListener
    • 的像HttpListener,這實現了I/O完成端口爲您
    • 如果你想爲一個連接只做一次(如復auth),你可以這樣做,因爲你知道何時打開套接字;但是,您可能不希望依靠這種因其他原因(代理服務器和負載平衡器可以在同一插座發送來自多個用戶的請求)的TcpListener對比的
  • 缺點HttpListener
    • 你必須提供一個HTTP頭解析器
    • 您必須驗證HTTP請求是軋製對自己
      • 無有效
    • 優勢這100%是我可以想到,與使用TcpListener相比
  • 將這100%自行滾動的缺點
    • 您可能會在您的網絡層代碼中引入大量不必要/不正確的鎖,這些鎖在一次測試單個請求的性能時不會導致任何問題,但會導致負載下的性能真正受損。這需要一段時間才能找到並修復它們。
    • 我們在項目中自行推出了這個功能,並且我們實現了與HttpListener相同的性能,其中有更多的編碼月份和不可維護的結果代碼庫。我們將其解開,並用HttpListener替換了所有的自定義代碼,沒有任何負面的性能影響,而且維護的代碼也少得多。

2016年11月更新:HttpListener工作得非常好,從遠程計算機接收業務時。但是,當客戶端位於本地主機上時,對於大型有效負載,HttpListener性能不佳,性能不佳。其原因部分是因爲HttpListener使用的是http.sys,它是一個內核模塊,顯然這個實現會產生幾個額外的正文數據副本。例如,從C#中的一個數組複製100 MB到另一個數組需要35 ms,而從本地客戶端向HttpListener發佈100 MB需要350 ms(是的,長10倍)。在這種情況下切換到Mono的HttpListener將時間降低到250毫秒。與Socket客戶端一起使用TcpListener需要180 ms。使用MemoryMappedFiles替換CircularBuffer的套接字使用需要55 ms。因此,當從本地機器訪問時,HttpListener對於大型有效載荷不太適用。注意:如果您嘗試重現此測試,則需要注意測量時差。 Stern開始發送數據,並且在接收過程中完成數組填充時,由於某些Send/Write方法幾乎立即返回而沒有發送任何數據(您可以通過發送一個零數組然後寫入一組數據數組的背面朝前;您將收到幾乎所有的數據,證明數據在函數返回後很長時間才發送)。

上HttpListener的本地機器性能赤字VS Mono的HttpListener更多細節從這裏我的一個同事: https://www.linkedin.com/pulse/http-inefficiency-dominika-blach

+0

很好的答案。在我的情況下,我想知道爲什麼我的客戶在幾百個連接後停止發送消息。我使用HttpListener作爲客戶端的WebRequest服務器。過了一段時間,他們只是簡單的停下來,沒有錯誤,看起來沒有資源可用。使用'ServicePointManager.DefaultConnectionLimit'和'ServicePointManager.MaxServicePoints'來玩這個功能並沒有幫助,所以在幾百次連接之後,我得到了同樣的錯誤。我嘗試過KeepAlive,但沒有運氣。任何想法?謝謝。 – GBrian

+2

您很可能沒有在一端或兩端正確關閉請求和響應,或者您在客戶端使用了線程池(例如通過使用定時器),並且正在從該線程池線程中拋出異常。一旦線程池線程完成,它就不會被重新創建。一旦用完線程池線程,任何使用它們的對象(如Timer對象)都不再有效。 – huntharo

+0

檢查我發佈的HttpListener示例代碼,作爲以下問題的答案。看看你是否以相同的方式處理請求,或者使用它來創建服務器的新版本,並查看問題是否存在。 http://stackoverflow.com/questions/10485985/bad-performance-when-offering-files-to-download-with-httplistener/19202175#19202175 – huntharo