英文:
How can I keep reading using net Conn Read method
问题
我正在创建一个简单的聊天服务器作为个人项目,以学习Go语言中的net包和一些并发操作。我的第一个想法是让服务器打印使用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 {
// 读取缓冲区
blen, err := conn.Read(buffer)
if err != nil {
log.Fatal(err)
}
message := string(buffer[:blen])
if message == "/quit" {
fmt.Println("收到退出命令。再见。")
return
}
if blen > 0 {
fmt.Println(message)
buffer = buffer[:0]
}
}
}
// Run 启动服务器。管理加入和离开聊天室
func (s *Server) Run() {
// 监听TCP端口2016
listener, err := net.Listen("tcp", ":2016")
if err != nil {
log.Fatal(err)
}
defer listener.Close()
for {
// 等待连接
conn, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
go s.messageReader(conn)
}
}
如果我从一个新的客户端发送一条新消息,它可以正常打印,但如果我发送另一条消息,它就不起作用了。我漏掉了什么?我需要重置Conn,还是关闭它并生成一个新的?
英文:
I'm creating a simple chat server as a personal project to learn net package and some concurrency in go. My 1st idea is to make the server print whatever is send using nc command echo -n "hello" | nc -w1 -4 localhost 2016 -p 61865
. However after the 1st read my code ignores the subsequent messages.
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)
}
}
If I send a new message from a new client it prints without problems but if I send another one it does nothing. What am I missing do I need to reset the Conn or close it and spawn a new one?
答案1
得分: 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
返回一个完整或单独的消息。你需要有一种更高级的协议来界定流中的消息。
英文:
After printing your message, you slice buffer
down to zero length. You can't read any data into a zero-length slice. There's no reason to re-slice your read buffer at all.
You also need to handle the read bytes before checking for errors, as io.EOF
can be returned on a successful read.
You shouldn't use log.Fatal
in the server's read loop, as that calls os.Exit
A working messageReader
body might look like:
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
}
}
You should note though that because you're not using any sort of framing protocol here, you can't guarantee that each conn.Read
returns a complete or single message. You need to have some sort of higher-level protocol to delimit messages in your stream.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论