2012-04-25 193 views
2

我是新來的套接字,並嘗試通過TCP套接字創建連接池。我的實現發送32位長度,然後爲每個呼叫發送二進制消息。但我有時遇到問題,有時讀者從服務器接收以前的響應(可能發生在客戶端關閉並在發送錯誤時重新建立套接字)。如何在新請求之前刷新套接字(前一個調用的剩餘字節)。任何建議?TCP連接池

編輯:我知道tcp總是流0,如果我發送消息之前的字節(1),所以我可以有一個刷新函數來檢查新的調用之前,套接字不是空的。

+0

歡迎來到SO!如果你能顯示一些你的代碼,那將是非常棒的。 – vyegorov 2012-04-25 19:20:38

回答

8

文章實際問幾個問題:

  • 如何管理一個連接池?
  • 如何處理插座上的通信?

這些實際上是兩回事。連接池只是管理一組連接的一種方式。實現一個簡單的方法是使用一類如:

package netpool 

    import (
     "net" 
    ) 

    const MaxConnections = 3 

    type Error string 

    func (e Error) Error() string { 
     return string(e) 
    } 

    var ErrMaxConn = Error("Maximum connections reached") 

    type Netpool struct { 
     name string 
     conns int 
     free []net.Conn 
    } 

    func NewNetpool(name string) *Netpool { 
     return &Netpool{ 
      name: name, 
     } 
    } 

    func (n *Netpool) Open() (conn net.Conn, err error) { 
     if n.conns >= MaxConnections && len(n.free) == 0 { 
      return nil, ErrMaxConn 
     } 

     if len(n.free) > 0 { 
      // return the first free connection in the pool 
      conn = n.free[0] 
      n.free = n.free[1:] 
     } else { 
      addr, err := net.ResolveTCPAddr("tcp", n.name) 
      if err != nil { 
       return nil, err 
      } 
      conn, err = net.DialTCP("tcp", nil, addr) 
      if err != nil { 
       return nil, err 
      } 
      n.conns += 1 
     } 
     return conn, err 
    } 

    func (n *Netpool) Close(conn net.Conn) error { 
     n.free = append(n.free, conn) 
     return nil 
    } 

我創建了一個獨立的類在這裏。它通常會作爲MyHTTPHost或MyDatabase等更高級別類的一部分來實現。

在這個簡單的實現中,不會跟蹤通過netpool.Open()返回的連接。可以通過調用Open()來泄漏連接,然後關閉netpool.Close()之外的連接。例如,如果要保存活動和非活動池,可以跟蹤它們,這可以解決此問題。

一對夫婦的其他東西,你可能要添加到池的實現:

  • 線程保護(使用sync.Mutex,例如)不活動的部分長度後
  • 收盤在freepool連接
  • 錯誤檢查,以確保封閉的連接仍然有效

一旦你有一個連接,你可以調用正常讀寫就可以了。要清除套接字上的所有未完成數據,只需使用ioutil.ReadAll()輔助函數即可。默認情況下,如果沒有可用的數據,它將無限期地阻塞。爲了避免這種情況,使用添加讀取超時:

conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) 
    _, err = ioutil.ReadAll(conn) 
    neterr, ok := err.(net.Error) 
    if ok && neterr.Timeout() { 
     err = nil // timeout isn't an error in this case 
    } 
    if err != nil { 
     // handle the error case. 
    } 

如果有正在等待這將從給定的連接讀取所有數據,如果沒有數據待處理500毫秒後,將返回一個I/O超時錯誤。

類型聲明是必需的,因爲ioutil.ReadAll()返回一個Error接口,而不是一個net.Error接口,我們需要後者能夠輕鬆地找出是否由於超時而返回調用。

+0

只是一個想法...或者open()需要MaxConnections(1)類型的實際最大連接數和一個最大連接池數;或者(2)刪除頂部的if並允許儘可能多的連接,只有在池滿後才能正確關閉它們。 – Richard 2015-04-08 12:12:32