2012-04-25 128 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