Go语言同一条TCP连接多次调用Write无法收到全部数据如何解决
问题原因
- 服务端连接处理逻辑错误:你当前的服务端在
Accept拿到一个客户端连接后,仅执行一次Read调用,读取到第一份数据后就回到外层循环等待新连接,没有持续读取当前连接上的后续数据,自然收不到第二次Write的内容。 - 主进程提前退出:你示例代码中客户端两次
Write执行完成后,main函数直接执行完毕,整个进程退出,可能存在第二次写入的数据还没来得及完全发送到服务端进程就终止的情况。 Read返回值未处理:你没有接收Read方法返回的实际读取字节数,直接把整个1024字节的数组转字符串,会附带大量空字符,也无法判断连接是否断开。
修复方案
第一步:调整服务端连接处理逻辑
Accept到新连接后,启动独立goroutine循环读取该连接的所有数据,直到连接断开,修复后的完整可运行代码如下:
package main import ( "io" "log" "net" "fmt" ) func main() { l, err := net.Listen("tcp", "localhost:1234") if err != nil { log.Fatal(err) } defer l.Close() go func() { for { c, err := l.Accept() if err != nil { log.Fatal(err) } // 每个连接启动独立goroutine处理 go func(conn net.Conn) { defer conn.Close() b := make([]byte, 1024) for { // 循环读取当前连接的所有数据 n, err := conn.Read(b) if err != nil { if err != io.EOF { log.Println("read error:", err) } return } // 仅转换实际读取到的n个字节 fmt.Println(string(b[:n])) } }(c) } }() conn, err := net.Dial("tcp", "localhost:1234") if err != nil { log.Fatal(err) } _, err = conn.Write([]byte("hello")) if err != nil { log.Fatal(err) } _, err = conn.Write([]byte("world")) if err != nil { log.Fatal(err) } // 阻塞主goroutine,避免进程直接退出 select {} }
第二步:可选的数据包边界处理
TCP是面向字节流的协议,没有内置数据包边界,你两次调用Write的hello和world可能会被服务端一次Read合并读到,输出为helloworld。如果你需要严格区分两个独立的数据包,需要自己实现拆包逻辑,常见实现方式:
- 固定分隔符:比如每个数据包末尾加
\n作为边界,服务端按分隔符切割数据 - 固定长度包头:包头存储后续数据包的长度,服务端先读包头拿到长度,再读取对应长度的数据
- TLV格式(类型+长度+值):更灵活的结构化数据包格式
内容的提问来源于stack exchange,提问作者Ado Ren
相关产品推荐
相关产品推荐

