如何使用网络连接的Read方法来持续读取数据?

huangapple go评论82阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2017年2月9日 10:02:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/42126978.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定