Golang中TCP数据传输不全问题排查与解决
Golang中TCP数据传输不全问题排查与解决 你好,
我正在编写服务器和客户端程序,但在测试过程中发现了一个令人不快的问题:在某些时刻,客户端和服务器之间的通信会卡住。有时这种情况发生在第一对消息之后,有时则发生得更晚。任何地方都没有抛出错误,只是服务器发送了消息,但客户端没有收到。
未完成的代码:
服务器:https://gist.github.com/matejstrnad/a25247788c1d5cb9f34a9fc3485ac120
客户端:https://gist.github.com/matejstrnad/cc27f76fd69b929665a7a6542f2c8682
有时,这个问题发生在服务器第113行和客户端第57行的消息上;有时也发生在发送公钥后到达服务器的“ok”消息上,即服务器第59行和客户端第64行。
我该如何修复这个问题?错误在哪里?
另外,我为我的英语道歉,我正在学习它。
更多关于Golang中TCP数据传输不全问题排查与解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang中TCP数据传输不全问题排查与解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
问题出在TCP消息边界处理上。你的代码假设每次Read()调用都能读取完整的消息,但TCP是流式协议,数据可能被拆分或合并传输。
以下是修复后的关键代码示例:
服务器端修复:
func readMessage(conn net.Conn) ([]byte, error) {
// 先读取消息长度(4字节)
lengthBuf := make([]byte, 4)
_, err := io.ReadFull(conn, lengthBuf)
if err != nil {
return nil, err
}
length := binary.BigEndian.Uint32(lengthBuf)
// 根据长度读取消息体
messageBuf := make([]byte, length)
_, err = io.ReadFull(conn, messageBuf)
if err != nil {
return nil, err
}
return messageBuf, nil
}
func writeMessage(conn net.Conn, data []byte) error {
// 先发送消息长度(4字节)
length := uint32(len(data))
lengthBuf := make([]byte, 4)
binary.BigEndian.PutUint32(lengthBuf, length)
_, err := conn.Write(lengthBuf)
if err != nil {
return err
}
// 发送消息体
_, err = conn.Write(data)
return err
}
客户端修复:
// 使用相同的readMessage和writeMessage函数
// 替换原来的conn.Read和conn.Write调用
// 发送消息示例:
err = writeMessage(conn, []byte("ok"))
if err != nil {
log.Printf("Write failed: %v", err)
return
}
// 接收消息示例:
msg, err := readMessage(conn)
if err != nil {
log.Printf("Read failed: %v", err)
return
}
在你的代码中需要修改的地方:
- 服务器第59行附近:
// 原代码:
n, err := conn.Read(buffer)
// 改为:
msg, err := readMessage(conn)
- 服务器第113行附近:
// 原代码:
_, err = conn.Write([]byte("ok"))
// 改为:
err = writeMessage(conn, []byte("ok"))
- 客户端第57行和第64行附近进行同样的修改。
这个修复方案通过添加消息长度前缀来确保完整消息的传输。io.ReadFull会阻塞直到读取到指定数量的字节,避免了数据不完整的问题。

