1

我有一个监听 TCP 连接的 go-routine,并在通道上将这些连接发送回主循环。我在 go-routine 中执行此操作的原因是使此侦听非阻塞并能够同时处理活动连接。

我已经使用带有空默认情况的 select 语句实现了这一点,如下所示:

go pollTcpConnections(listener, rawConnections)

for {
    // Check for new connections (non-blocking)
    select {
    case tcpConn := <-rawConnections:
        currentCon := NewClientConnection()
        pendingConnections.PushBack(currentCon)
        fmt.Println(currentCon)
        go currentCon.Routine(tcpConn)
    default:
    }
   // ... handle active connections
}

这是我的 pollTcpConnections 例程:

func pollTcpConnections(listener net.Listener, rawConnections chan net.Conn) {
  for {
    conn, err := listener.Accept()  // this blocks, afaik
    if(err != nil) {
        checkError(err)
    }
    fmt.Println("New connection")
    rawConnections<-conn
  }
}

问题是我从来没有收到过这些联系。如果我以阻塞方式执行此操作,如下所示:

for {
    tcpConn := <-rawConnections
// ...
}

我收到了连接,但它阻塞了......我也尝试过缓冲通道,但同样的事情发生了。我在这里想念什么?

4

1 回答 1

1

根据现有代码,很难说出为什么您没有看到任何连接。您的示例的一个问题是您default的语句中有一个空的情况select,然后我们看不到在此发生的其他情况for环形。按照您编写的方式,该循环可能永远不会屈服于调度程序。您基本上是在说“从频道获取东西。没有?好吧,重新开始。从频道获取东西!”,但您实际上从不等待。当你做一些阻塞你的 goroutine 的操作时,那个 goroutine 让给调度程序。因此,当您以正常方式读取通道时,如果没有要读取的值,则该 goroutine 将被阻塞读取。由于它被阻塞了,它也让调度器允许其他 goroutines 继续在底层线程上执行。我很确定这就是为什么你select的空虚default正在破坏的原因;您正在导致该 goroutine 在循环中无限for循环,而不会屈服于调度程序。

目前尚不清楚它的作用pendingConnections是什么,或者是否需要它。

从行为中无法分辨的另一件事是您的checkError函数的作用。例如,它不会继续到for循环的顶部或保释。

无论如何,看起来这比它需要的更复杂。只需有一个将新连接作为参数的函数,然后在连接时在新的 goroutine 中启动它。我总是这样写:

func handleConnection(c net.Conn) {
    // do something with your connection here.
}

for {
    // Wait for a connection.
    conn, err := l.Accept()
    if err != nil {
        // do something with your error.  You probably want to break or return here.
        break
    }
    // handle each connection in a new goroutine
    go handleConnection(conn)
}

这或多或少正是他们在文档中所做的。

于 2013-02-01T15:55:03.947 回答