如何使用net Conn Read方法继续阅读

时间:2017-02-09 02:02:03

标签: go

我正在创建一个简单的聊天服务器作为个人项目来学习网络包和一些并发性。我的第一个想法是使用nc命令echo -n "hello" | nc -w1 -4 localhost 2016 -p 61865使服务器打印发送的内容。但是,在第一次读取后,我的代码忽略了后续消息。

func (s *Server) messageReader(conn net.Conn) {
defer conn.Close()
buffer := make([]byte, 1024)
for {
    //read buff
    blen, err := conn.Read(buffer)
    if err != nil {
        log.Fatal(err)
    }

    message := string(buffer[:blen])

    if message == "/quit" {
        fmt.Println("quit command received. Bye.")
        return
    }

    if blen > 0 {
        fmt.Println(message)
        buffer = buffer[:0]
    }
}
}

// Run Start up the server. Manages join and leave chat
func (s *Server) Run() {
// Listen on port TCP 2016
listener, err := net.Listen("tcp", ":2016")
if err != nil {
    log.Fatal(err)
}
defer listener.Close()

for {
    //wait for connection
    conn, err := listener.Accept()
    if err != nil {
        log.Fatal(err)
    }

    go s.messageReader(conn)

}
}

如果我从新客户端发送新消息,它会打印没有问题,但如果我发送另一个消息,它什么都不做。我错过了什么?我需要重置Conn还是关闭它并产生一个新的?

1 个答案:

答案 0 :(得分:3)

打印完消息后,将buffer切片为零长度。您无法将任何数据读入零长度切片。根本没有理由重新切片读取缓冲区。

您还需要在检查错误之前处理读取字节,因为成功读取时可以返回io.EOF

您不应在服务器的读取循环中使用log.Fatal,因为它会调用os.Exit

工作messageReader正文可能如下:

defer conn.Close()
buffer := make([]byte, 1024)
for {
    n, err := conn.Read(buffer)
    message := string(buffer[:n])

    if message == "/quit" {
        fmt.Println("quit command received. Bye.")
        return
    }

    if n > 0 {
        fmt.Println(message)
    }

    if err != nil {
        log.Println(err)
        return
    }
}

您应该注意,因为您在此处未使用任何类型的框架协议,因此无法保证每个conn.Read都返回完整或单个邮件。您需要使用某种更高级别的协议来分隔流中的消息。