【问题标题】:Golang TCP Client does not receive data from server, hangs/blocks on conn.Read()Golang TCP 客户端没有从服务器接收数据,在 conn.Read() 上挂起/阻塞
【发布时间】:2016-12-03 10:15:50
【问题描述】:

我正在深入研究 Go 的网络方面,我想我会从 TCP 客户端和服务器开始。

我能够让客户端连接到服务器并成功发送一条简单的消息(“Hello”)。但是,我无法让服务器发回响应(或让客户端读取响应)。

这里是代码。

服务器

Address := "localhost:9999"
Addr, err := net.ResolveTCPAddr("tcp", Address)
if err != nil {
    log.Fatal(err)
}

listener, err := net.ListenTCP("tcp", Addr)
if err != nil {
    log.Fatal(err)
}
defer listener.Close()

//server loop
for {
    conn, err := listener.Accept()
    if err != nil {
        continue
    }

    go handle(conn)
}

func handle(c net.Conn) {

    totalBytes, message := connRead(c)
    fmt.Println(c.RemoteAddr())

    fmt.Println(string(message[:totalBytes]))

    c.Write([]byte("Hi"))
    fmt.Println("Replied")
    c.Close()
}

func connRead(c net.Conn) (int, []byte) {
    buffer := make([]byte, 4096)
    totalBytes := 0

    for {
        n, err := c.Read(buffer)
        totalBytes += n
        if err != nil {
            if err != io.EOF {
                log.Printf("Read error: %s", err)
            }
            break
        }

    }
    return totalBytes, buffer
}

客户

    tcpAddr, err := net.ResolveTCPAddr("tcp", "localhost:9999")
    if err != nil {
        log.Fatal(err)
    }
    conn, err := net.DialTCP("tcp", nil, tcpAddr)
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    _, err = conn.Write([]byte("Hello"))
    if err != nil {
        log.Fatal(err)
    }

    tBytes, resp := connRead(conn)
    fmt.Println(tBytes)
    fmt.Println(string(resp[:tBytes]))

func connRead(c net.Conn) (int, []byte) {
    buffer := make([]byte, 4096)
    totalBytes := 0

    for {
        fmt.Println("Stuck?")
        n, err := c.Read(buffer)
        fmt.Println("Stuck.")
        totalBytes += n
        fmt.Println(totalBytes)
        if err != nil {
            if err != io.EOF {
                log.Printf("Read error: %s", err)
            }
            break
        }

    }
    return totalBytes, buffer
}

据我所知,这不是服务器的问题。当我运行客户端时,一切都在fmt.Println("Stuck?") 之后停止。这让我相信它在某种程度上搞砸了n, err := c.Read(buffer) 声明。在我 Ctrl-C 客户端之前,服务器甚至不会打印出消息长度(5)和消息(“Hello”)。如果我在客户端注释掉读取和打印,那么事情就会顺利进行。

我尝试在谷歌上搜索答案,但没有任何结果。

我做错了什么?我在客户端中使用 conn.Read() 错误吗?

编辑:

我确实可以访问 Linux,所以这里是相关功能的 SIGQUIT 转储。

服务器

http://pastebin.com/itevngCq

客户

http://pastebin.com/XLiKqkvs

【问题讨论】:

  • 一目了然,它看起来像是客户端和服务器阻止读取连接上的 EOF。向正在运行的应用程序发送 SIQUIT 以找出它们被阻止的位置。
  • 我在 Win 7 上,它不支持 SIGQUIT。
  • 两个程序在读取时都被阻止。一个或两个对等点应该close the write side 的连接以解除阻塞另一个对等点。或者,您可以添加消息框架并在阅读完整消息后停止阅读。
  • 如果服务器不打印 msg 长度,你怎么知道它正在接收一些东西?是 connRead 还是 conn.Read?

标签: go tcp network-programming


【解决方案1】:
for {
    n, err := c.Read(buffer)
    totalBytes += n
    if err != nil {
        if err != io.EOF {
            log.Printf("Read error: %s", err)
        }
        break
    }

}

这是因为您正在从连接中读取,直到出现 EOF 错误

conn.Write([]byte("Hello"))

在您真正关闭连接之前,上述语句根本不会到达 EOF

在客户端按下 ctrl+c 连接将被关闭,所以 EOF 发生在服务器端,这就是它退出服务器端循环并打印这些的原因

127.0.0.1:****
Hello
Replied

如果你想完成这项工作,你不应该在 EOF 之前阅读连接

还有很多其他的选择

  1. 选择一个分隔符并在服务器上读取,直到分隔符出现并在此之后回复。看看这个link
  2. 在发送实际消息之前先从客户端读取要读取的字节数,首先从服务器端读取要读取的字节数,然后从连接中读取这些字节数

【讨论】:

  • 谢谢。我决定使用替代编号 1。但是,现在当我在收到服务器的响应后尝试从同一个客户端发送另一条消息时,服务器似乎没有收到第二条消息。
  • @JimDoe 你能分享你写的源代码,以便我可以帮助你
  • 当然!客户端:pastebin.com/k3B0zuVr 服务器:pastebin.com/9AXXjVwx 第二条消息发送。但我从服务器返回零字节。
  • 在for循环句柄连接的服务器端,您为每个请求调用listener.Accept(),因此每次从客户端发送请求时都需要调用net.DialTCP("tcp", nil, tcpAddr)
  • @Tej 为什么conn.Write([]byte("Hello")) 永远不会到达 EOF?
猜你喜欢
  • 1970-01-01
  • 2012-08-24
  • 1970-01-01
  • 1970-01-01
  • 2012-03-05
  • 2021-02-19
  • 2016-03-18
  • 1970-01-01
  • 2017-12-29
相关资源
最近更新 更多