通过TCP链接传输结构体的Golang实现方法

通过TCP链接传输结构体的Golang实现方法 你好! 我想了解,在实现效率和简洁性方面,传输特定类型的消息的最佳方式是什么?

我想解决的问题是,我希望每条消息都具有 {标题, 正文, 时间戳} 这样的形式,但到目前为止,我使用的是缓冲区,并且只发送字节消息。

在我的使用场景中,效率对我很重要。我听说过 protobuf。它对我来说是最佳解决方案吗?

关于这个主题的第二个问题是,如果我在 Windows 机器上进行开发,但使用 WSL 与 Ubuntu 终端交互,我应该安装 Windows 版本还是 Linux 版本的 protoc(protobuf 编译器)?

1 回复

更多关于通过TCP链接传输结构体的Golang实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


对于通过TCP传输结构体,Go语言中有几种高效且简洁的实现方式。以下是针对你需求的具体实现:

1. 使用encoding/gob(Go原生方案)

这是Go语言内置的二进制序列化方案,特别适合Go-to-Go通信:

package main

import (
    "encoding/gob"
    "fmt"
    "net"
    "time"
)

// 定义消息结构体
type Message struct {
    Title     string
    Body      string
    Timestamp time.Time
}

// 发送消息
func sendMessage(conn net.Conn, msg Message) error {
    encoder := gob.NewEncoder(conn)
    return encoder.Encode(msg)
}

// 接收消息
func receiveMessage(conn net.Conn) (Message, error) {
    var msg Message
    decoder := gob.NewDecoder(conn)
    err := decoder.Decode(&msg)
    return msg, err
}

// 服务器端示例
func server() {
    ln, _ := net.Listen("tcp", ":8080")
    conn, _ := ln.Accept()
    
    msg := Message{
        Title:     "测试消息",
        Body:      "这是消息正文",
        Timestamp: time.Now(),
    }
    
    sendMessage(conn, msg)
}

// 客户端示例
func client() {
    conn, _ := net.Dial("tcp", "localhost:8080")
    
    msg, _ := receiveMessage(conn)
    fmt.Printf("收到消息: %+v\n", msg)
}

2. 使用Protocol Buffers(跨语言方案)

这是Google的高效二进制序列化格式,适合跨语言通信:

首先定义proto文件(message.proto):

syntax = "proto3";

package main;

option go_package = "./";

message Message {
    string title = 1;
    string body = 2;
    int64 timestamp = 3;
}

生成Go代码:

# 在WSL中安装Linux版本的protoc
sudo apt-get install protobuf-compiler
protoc --go_out=. message.proto

Go实现代码:

package main

import (
    "fmt"
    "net"
    "time"
)

// 发送protobuf消息
func sendProtobufMessage(conn net.Conn, msg *Message) error {
    data, err := proto.Marshal(msg)
    if err != nil {
        return err
    }
    
    // 先发送消息长度
    length := uint32(len(data))
    err = binary.Write(conn, binary.BigEndian, length)
    if err != nil {
        return err
    }
    
    // 发送消息体
    _, err = conn.Write(data)
    return err
}

// 接收protobuf消息
func receiveProtobufMessage(conn net.Conn) (*Message, error) {
    // 读取消息长度
    var length uint32
    err := binary.Read(conn, binary.BigEndian, &length)
    if err != nil {
        return nil, err
    }
    
    // 读取消息体
    data := make([]byte, length)
    _, err = io.ReadFull(conn, data)
    if err != nil {
        return nil, err
    }
    
    msg := &Message{}
    err = proto.Unmarshal(data, msg)
    return msg, err
}

// 使用示例
func example() {
    msg := &Message{
        Title:     "Protobuf消息",
        Body:      "这是protobuf格式的消息",
        Timestamp: time.Now().Unix(),
    }
    
    // 在TCP连接上发送
    conn, _ := net.Dial("tcp", "localhost:8080")
    sendProtobufMessage(conn, msg)
}

3. 使用JSON(可读性方案)

如果需要可读性或与其他系统集成,可以使用JSON:

package main

import (
    "encoding/json"
    "fmt"
    "net"
    "time"
)

// JSON消息传输
func sendJSONMessage(conn net.Conn, msg Message) error {
    encoder := json.NewEncoder(conn)
    return encoder.Encode(msg)
}

func receiveJSONMessage(conn net.Conn) (Message, error) {
    var msg Message
    decoder := json.NewDecoder(conn)
    err := decoder.Decode(&msg)
    return msg, err
}

性能对比

  1. encoding/gob

    • 优点:Go原生支持,无需额外依赖,序列化/反序列化速度快
    • 缺点:仅适用于Go语言间通信
  2. Protocol Buffers

    • 优点:跨语言支持,二进制格式高效,向后兼容性好
    • 缺点:需要.proto文件定义和protoc编译
  3. JSON

    • 优点:可读性好,广泛支持
    • 缺点:性能较低,数据体积较大

关于protoc安装

在WSL开发环境中,应该安装Linux版本的protoc,因为:

  • WSL运行的是Linux二进制文件
  • 你的Go代码将在Linux环境中编译和执行
  • 保持开发环境的一致性

安装命令:

# 在WSL的Ubuntu中
sudo apt-get update
sudo apt-get install protobuf-compiler
protoc --version  # 验证安装

对于你的使用场景,如果主要是Go语言间通信且追求最高效率,推荐使用encoding/gob。如果需要跨语言支持或与其他系统集成,Protocol Buffers是最佳选择。

回到顶部