Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 如何使用网络连接读取方法保持读取_Go - Fatal编程技术网

Go 如何使用网络连接读取方法保持读取

Go 如何使用网络连接读取方法保持读取,go,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

我正在创建一个简单的聊天服务器,作为一个个人项目来学习网络包和围棋中的一些并发性。我的第一个想法是让服务器使用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还是关闭它并生成一个新的Conn?

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

您还需要在检查错误之前处理读取的字节,因为成功读取时可以返回
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
都返回完整或单个消息。您需要某种更高级的协议来界定流中的消息

在打印消息后,将
缓冲区
切成零长度。无法将任何数据读入零长度切片。根本没有理由对读取缓冲区进行重新切片

您还需要在检查错误之前处理读取的字节,因为成功读取时可以返回
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
都返回完整或单个消息。您需要某种更高级的协议来界定流中的消息

您建议在标准库中使用什么协议
net/http
可以工作,但如果我没有弄错的话,http不是消息传递协议。我试图保持小范围,但我也想知道可以做什么或如何做。谢谢你回答中的额外内容。非常有用的知识。@cmejia:协议取决于您的需要。最常见的框架方法可能是简单的长度前缀字符串。您还可以设置一个分隔符,确保它不会出现在邮件中。包含点编码格式,使用
\r\n
分隔行,使用
\r\n
表示消息结束,以及MIME格式键值。您建议在标准库中使用什么协议
net/http
可以工作,但如果我没有弄错的话,http不是消息传递协议。我试图保持小范围,但我也想知道可以做什么或如何做。谢谢你回答中的额外内容。非常有用的知识。@cmejia:协议取决于您的需要。最常见的框架方法可能是简单的长度前缀字符串。您还可以设置一个分隔符,确保它不会出现在邮件中。包含点编码格式,使用
\r\n
分隔行,使用
\r\n
表示消息结束,以及MIME格式键值。