当前位置: 首页 > 面试题库 >

TCP接受和并发模型

翟理
2023-03-14
问题内容

看着net.TCPListener。鉴于Go并发范例,人们可能希望将此系统功能实现为一个渠道,以便您chan *net.Conn从某个Listen()功能或类似的功能中获得一个。

但是似乎Accept()是这样,而且就像系统接受一样,它只是阻塞。除非它残废,是因为:

  • 您无法使用适当的select(),因为go偏爱频道
  • 无法为服务器套接字设置阻止选项。

所以我正在做类似的事情:

    acceptChannel = make(chan *Connection)
    go func() {
      for {
       rw, err := listener.Accept()
       if err != nil { ... handle error ... close(acceptChannel) ... return }
       s.acceptChannel <-&Connection{tcpConn: rw, .... }
      }
    }()

只是为了使我可以在选择中使用多个服务器套接字,或者将对Accept()的等待与其他通道复用。我想念什么吗?我是Go的新手,所以我可能会忽略一些东西-
但是Go真的不使用自己的并发范例来实现自己的阻塞系统功能吗?我真的想为每个要监听的套接字(可能是数百个或数千个)使用一个单独的goroutine吗?这是要使用的正确习惯用法,还是有更好的方法?


问题答案:

您的代码很好。您甚至可以进一步替换:

s.acceptChannel <-&Connection{tcpConn: rw, .... }

与:

go handleConnection(&Connection{tcpConn: rw, .... })

如注释中所述,例程不是系统线程,而是由Go运行时管理的轻量级线程。当为每个连接创建例程时,可以轻松地使用阻塞操作,这些操作更易于实现。然后,运行时程序将为您
选择 例程,因此,您正在寻找的行为只是存在于该语言中的其他地方。您看不到它,但是无处不在。

现在,如果您需要更复杂的功能,并且根据我们的对话,实现与超时类似的选择,您将完全按照您的建议进行操作:将所有新连接推送到一个通道,并使用计时器对其进行多路复用。这似乎是Go中要走的路。

请注意,如果 其中一个 接收器发生故障,您将无法关闭接收通道,因为另一个接收器在写入时会出现恐慌。

我的(更完整的)示例:

newConns := make(chan net.Conn)

// For every listener spawn the following routine
go func(l net.Listener) {
    for {
        c, err := l.Accept()
        if err != nil {
            // handle error (and then for example indicate acceptor is down)
            newConns <- nil
            return
        }
        newConns <- c
    }
}(listener)

for {
    select {
    case c := <-newConns:
        // new connection or nil if acceptor is down, in which case we should
        // do something (respawn, stop when everyone is down or just explode)
    case <-time.After(time.Minute):
        // timeout branch, no connection for a minute
    }
}


 类似资料:
  • 问题内容: 我一直在使用多个Raspberry Pi,Python和一些按钮/开关进行游戏。我的游戏需要一个中央服务器,该服务器向多个客户端发出命令。 我不是编程新手,而是Python和较低级网络通信的新手,在过去两天里,我一直迷失在如何精确编写服务器代码方面。 客户端程序是一个简单的socket.connect,然后等待发送数据。那里没有问题。 我很难确定确切的编写方式以及如何使服务器正常工作。

  • 我正在用C语言测试一些代码,发现TCP套接字调用有奇怪的行为。 > 我定义了一个监听线程,它同步地接受客户机,在接受客户机之后,它会在for循环中处理它,直到断开连接。因此,一次只处理一个客户机。所以我在一个循环中调用,然后在一个内部循环中调用,直到收到一个空缓冲区。 我与客户端启动5个线程,我调用,,最后 我在任何电话中都没有出错。一切似乎都很好。 然而,当我在服务器端打印收到的消息时,结果发现

  • 问题内容: 我正在尝试Go-并希望创建一个可以远程登录,发送命令和接收响应的TCP服务器。 上面的代码片段每次都会关闭连接,将我踢出终端会话。但是我真正想要的是能够保持连接打开以进行更多的I / O操作。如果我只是删除,则服务器似乎挂在某处,因为它不再获得任何响应。 我解决此问题的方法是让我的handleRequest方法无休止地循环,以便它在收到消息之前永远不会退出。这是否合适- 还是有更好的实

  • 下面的内容解释了一个理论上的模型。现代 JavaScript 引擎着重实现和优化了描述的几个语义。 运行时 下图是 JavaScript 运行时的可视化描述: 从图中可以看出,其主要包含了栈、堆、队列等数据结构。 栈 用于函数执行的「调用栈」,英文名为「call stack」。 function foo( b ) { var a = 10;​ return a + b + 11;}​funct

  • 问题内容: 在Go中,TCP连接(net.Conn)是io.ReadWriteCloser。我想通过模拟TCP连接来测试我的网络代码。我有两个要求: 要读取的数据存储在字符串中 每当写入数据时,我都希望将其存储在某种缓冲区中,以便以后使用 是否有数据结构或简单的方法? 问题答案: 为什么不使用?它是一种并且具有获取存储数据的方法。如果需要将其设置为,则可以定义自己的类型: 并定义一个方法: