Golang TCP Client不接收来自服务器的数据,挂起/阻止conn.Read()

时间:2016-07-28 20:33:33

标签: go tcp network-programming

我正在深入研究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客户端后,服务器甚至不会打印出messeage长度(5)和消息(“Hello”)。如果我在客户端注释掉读取和打印,那么事情就会顺利进行。

我尝试用谷歌搜索答案,但什么都没有出现。

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

修改

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

服务器

http://pastebin.com/itevngCq

客户端

http://pastebin.com/XLiKqkvs

1 个答案:

答案 0 :(得分:2)

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. 在发送实际消息之前发送要从客户端读取的字节数,首先读取从服务器端读取的字节数,然后从连接中读取那么多字节