2012-04-25 36 views
2

私はソケットが新しく、TCPソケットを介して接続プールを作成しようとしています。私の実装は、各呼び出しのバイナリメッセージを32ビットの長さを送信します。しかし、私はときどき読者がサーバーから以前の応答を受け取っている時に問題を抱えています(クライアントが送信エラーでソケットを閉じて再確立したときに起こる可能性があります)。新しい要求の前に、ソケット(前の呼び出しから残ったバイト)をどのようにフラッシュするのですか?なにか提案を?TCP接続プール

編集:tcpは常に0のストリームを受信しました。メッセージの前にバイト(1)を送信すれば、新しいコールの前にソケットが空でないかどうかを確認するフラッシュ機能を持つことができます。

+0

ようこそ!あなたのコードを少し見せてくれれば幸いです。 – vyegorov

答えて

8

あなたの投稿は、実際にいくつかの質問をする:

  • 接続プールを管理するためにどのように?
  • ソケットを介した通信を処理するにはどうすればよいですか?

これらは実際には2つの異なるものです。接続プールは、一連の接続を管理する単なる方法です。これを実装する簡単な方法は次のようなクラスです:

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を使用して、)

  • スレッディング保護の非アクティブのいくつかの長さの後にフリープール内の接続の
  • 閉会
  • あなたが接続されていたら、Readを呼び出すと、通常はそれを書くことができます

クローズ接続がまだ有効であることを確認するためにエラーチェック。ソケット上の残っているデータをすべて消去するには、単に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. 
    } 

いずれかが保留されている、またはデータが保留されなかった場合は、I/Oタイムアウトエラーで500ミリ秒後に戻ります場合、これは特定の接続からのすべてのデータを読み込みます。

iautil.ReadAll()はnet.ErrorインターフェイスではなくErrorインターフェイスを返すので、型アサーションが必要です。タイムアウトにより呼び出しが返されたかどうかを簡単に確認できるように、後者が必要です。

+0

ちょっと考えてみてください... open()は、実際の最大接続数と、プール内の最大接続数のMaxConnections(1)のタイプを必要とします。または(2)プールを一杯にした後、上部にあるifを取り外し、必要な数の接続を適切に閉じるだけです。 – Richard