//client.go
//发送数据
package main
import (
"bytes"
"encoding/binary"
"fmt"
"net"
)
type rpc_detail struct{
Version [2]byte //版本号
FunsLen uint32 //函数名长度
FunsName []byte
}
func main() {
obj := new(rpc_detail)
conn ,err := net.Dial("tcp","54.151.231.22:33122")
data := "get_data_detail-%d"
for i:=0;i < 1;i++{
send_data := fmt.Sprintf(data,i)
(*obj).Version[0] = 'v'
(*obj).Version[1] = '1'
(*obj).FunsLen = uint32(len(send_data))
(*obj).FunsName = []byte(send_data)
fmt.Printf("结构体:%+v\n",*obj)
buf := new(bytes.Buffer)
binary.Write(buf,binary.BigEndian,obj.Version)
binary.Write(buf,binary.BigEndian,obj.FunsLen)
binary.Write(buf,binary.BigEndian,obj.FunsName)
conn.Write(buf.Bytes())
fmt.Printf("输出:%+v,err:%+v\n",buf.Bytes(),err)
}
}
//服务端接收数据:
package main
import (
"fmt"
"net"
"bytes"
"encoding/binary"
"os"
"io"
)
func main() {
listener, err := net.Listen("tcp", ":33122")
if err != nil {
fmt.Println("Error listening:", err.Error())
os.Exit(1)
}
defer listener.Close()
fmt.Println("Server started, listening on port 33122")
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
continue
}
go handleConnection(conn)
}
}
type rpc_detail struct{
Version [2]byte //版本号
FunsLen uint32 //函数名长度
FunsName []byte
}
func unpack(b []byte)(obj *rpc_detail){
buf := bytes.NewReader(b)
obj = new(rpc_detail)
err := binary.Read(buf,binary.BigEndian,&obj.Version)
fmt.Printf("错误:%+v,版本:%+c%+c\n",err,(*obj).Version[0],(*obj).Version[1])
err = binary.Read(buf,binary.BigEndian,&(*obj).FunsLen)
fmt.Printf("错误:%+v,函数名长度:%+v\n",err,(*obj).FunsLen)
return
}
func handleConnection(conn net.Conn) {
defer conn.Close()
data := make([]byte,6)
//dataBuffer := bytes.NewReader(binaryData)
for {
_, err := io.ReadFull(conn, data)
if err != nil {
if err == io.EOF {
fmt.Println("Client disconnected")
return
} else {
fmt.Println("Error reading from client:", err.Error())
return
}
}
obj := unpack(data)
body_len := obj.FunsLen
body_buf := make([]byte,body_len)
_, err = io.ReadFull(conn, body_buf)
body_data := bytes.NewReader(body_buf)
err = binary.Read(body_data,binary.BigEndian,&(*obj).FunsName)
fmt.Printf("主体:%+v,err:%+v\n",(*obj).FunsName,err)
}
}
我遇到的问题是FunsName打印是空数据,但是读取到body_buf里了:body_buf:[103 101 116 95 100 97 116 97 95 100 101 116 97 105 108 45 48],主体:[],err:<nil>
golang tcp协议解析
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
5条回答 默认 最新
关注让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。
如果答案让您满意,请采纳、点赞、关注,非常感谢!
.
每日一句正能量,让它带给您好心情:每一个清晨,都是一个新的开始,充满无限可能。
.根据你的代码分析,问题出现在服务端解析数据时。主要问题有两个:
问题分析
- 固定读取6字节导致数据不完整:服务端每次固定读取6字节,但实际数据可能超过这个长度
- FunsName字段解析错误:在
unpack函数中只解析了Version和FunsLen,但FunsName的解析逻辑有问题
解决方案
修改服务端代码:
package main import ( "fmt" "net" "bytes" "encoding/binary" "os" "io" ) func main() { listener, err := net.Listen("tcp", ":33122") if err != nil { fmt.Println("Error listening:", err.Error()) os.Exit(1) } defer listener.Close() fmt.Println("Server started, listening on port 33122") for { conn, err := listener.Accept() if err != nil { fmt.Println("Error accepting: ", err.Error()) continue } go handleConnection(conn) } } type rpc_detail struct { Version [2]byte //版本号 FunsLen uint32 //函数名长度 FunsName []byte } func unpackHeader(data []byte) (*rpc_detail, error) { if len(data) < 6 { // Version(2字节) + FunsLen(4字节) return nil, fmt.Errorf("header data too short") } obj := &rpc_detail{} buf := bytes.NewReader(data) // 读取版本号 err := binary.Read(buf, binary.BigEndian, &obj.Version) if err != nil { return nil, err } // 读取函数名长度 err = binary.Read(buf, binary.BigEndian, &obj.FunsLen) if err != nil { return nil, err } return obj, nil } func handleConnection(conn net.Conn) { defer conn.Close() for { // 先读取固定长度的头部数据 (2字节Version + 4字节FunsLen) header := make([]byte, 6) _, err := io.ReadFull(conn, header) if err != nil { if err == io.EOF { fmt.Println("Client disconnected") return } else { fmt.Println("Error reading header:", err.Error()) return } } // 解析头部 obj, err := unpackHeader(header) if err != nil { fmt.Println("Error unpacking header:", err.Error()) return } fmt.Printf("版本:%c%c, 函数名长度:%d\n", obj.Version[0], obj.Version[1], obj.FunsLen) // 根据长度读取函数名数据 if obj.FunsLen > 0 { obj.FunsName = make([]byte, obj.FunsLen) _, err = io.ReadFull(conn, obj.FunsName) if err != nil { fmt.Println("Error reading body:", err.Error()) return } fmt.Printf("函数名:%s\n", string(obj.FunsName)) } } }主要修改点
- 分离头部解析:将头部解析单独放在
unpackHeader函数中 - 正确读取流程:
- 先读取固定6字节头部(Version 2字节 + FunsLen 4字节)
- 解析头部获取FunsLen
- 根据FunsLen读取相应长度的函数名数据
- 直接赋值:直接将读取到的字节数据赋值给
obj.FunsName,不需要再次使用binary.Read
客户端代码优化建议
客户端代码也可以稍作优化:
// 在客户端main函数中,发送数据后可以添加读取服务器响应的逻辑 // 在conn.Write(buf.Bytes())后添加: // 读取服务器响应 response := make([]byte, 1024) n, err := conn.Read(response) if err != nil { fmt.Printf("读取响应错误: %v\n", err) } else { fmt.Printf("服务器响应: %s\n", string(response[:n])) }这样修改后,服务端应该能正确解析出函数名数据。
本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报