[Go]Golang引入Protobuffer

本文介绍了在Golang中使用Protobuffer的步骤,包括安装protobuffer环境,编译.proto文件,并提供了一个简单的客户端和服务端交互的例子。在编译.proto文件时,使用protoc-gen-go.exe生成Go代码,然后将生成的PBMessage.pb.go文件加入到Go项目中。在实际运行时,需要注意解码时传入buffer的长度应与数据长度一致,以避免错误。

准备

在Golang中使用Protobuffer非常简单。

1.安装protobuffer的环境

你可以选择直接github上下载proto源码然后自行编译,这部分教程一大把不再赘述。
为了省心(偷懒),我打包了一份protobuffer2.6版本的release版,还包括给C#和Go使用的可执行程序。
连接在:protobuffer2.6下载
解压之后你会看到如下文件结构:
这里写图片描述

bin文件夹是protobuffer的realease目录:

这里写图片描述

其中:

  • CodeGenerator.exe 是编译.proto并生成对应的C#代码的程序
  • protoc-gen-go.exe 是编译.proto并生成对应的Go代码的程序

在主目录写了两个批处理文件:

//CreatePacket-CSharp.bat
bin\CodeGenerator.exe PBMessage.proto --output output\csharp --preserve-names
//PBMessage.proto是输入的PB描述文件
//--ouput是命令参数 后边紧跟输出代码的目录
//--perserve-names是表示生成的代码使用自己在.proto描述的名字
//CreatePacket-Go.bat
bin\protoc.exe --go_out=output\go PBMessage.proto
//PBMessage.proto是输入的PB描述文件
//--go_out是命令参数 后边紧跟输出代码的目录

这里我的PBMessage.proto的描述如下:

package ProtobufPacket;

message CG_LOGIN_IN
{
    required int32 id = 1;
    required string account = 2;
    required string password = 3;
}

这里命名的package的名字是ProtobufPacket,对应的产生的go文件的packet名就是ProtobufferPacket,C#的命名空间是Protobuffer。

# 2.编译.proto文件

我们运行安装目录中的批处理文件,以go为例,我们得到名为PBMessage.pb.go的文件:

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: PBMessage.proto

/*
Package ProtobufPacket is a generated protocol buffer package.

It is generated from these files:
    PBMessage.proto

It has these top-level messages:
    CG_LOGIN_IN
*/
package ProtobufPacket

import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package

type CG_LOGIN_IN struct {
    Id               *int32  `protobuf:"varint,1,req,name=id" json:"id,omitempty"`
    Account          *string `protobuf:"bytes,2,req,name=account" json:"account,omitempty"`
    Password         *string `protobuf:"bytes,3,req,name=password" json:"password,omitempty"`
    XXX_unrecognized []byte  `json:"-"`
}

func (m *CG_LOGIN_IN) Reset()                    { *m = CG_LOGIN_IN{} }
func (m *CG_LOGIN_IN) String() string            { return proto.CompactTextString(m) }
func (*CG_LOGIN_IN) ProtoMessage()               {}
func (*CG_LOGIN_IN) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }

func (m *CG_LOGIN_IN) GetId() int32 {
    if m != nil && m.Id != nil {
        return *m.Id
    }
    return 0
}

func (m *CG_LOGIN_IN) GetAccount() string {
    if m != nil && m.Account != nil {
        return *m.Account
    }
    return ""
}

func (m *CG_LOGIN_IN) GetPassword() string {
    if m != nil && m.Password != nil {
        return *m.Password
    }
    return ""
}

func init() {
    proto.RegisterType((*CG_LOGIN_IN)(nil), "ProtobufPacket.CG_LOGIN_IN")
}

func init() { proto.RegisterFile("PBMessage.proto", fileDescriptor0) }

var fileDescriptor0 = []byte{
    // 115 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x0f, 0x70, 0xf2, 0x4d,
    0x2d, 0x2e, 0x4e, 0x4c, 0x4f, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x0b, 0x00, 0x51,
    0x49, 0xa5, 0x69, 0x01, 0x89, 0xc9, 0xd9, 0xa9, 0x25, 0x4a, 0x36, 0x5c, 0xdc, 0xce, 0xee, 0xf1,
    0x3e, 0xfe, 0xee, 0x9e, 0x7e, 0xf1, 0x9e, 0x7e, 0x42, 0x5c, 0x5c, 0x4c, 0x99, 0x29, 0x12, 0x8c,
    0x0a, 0x4c, 0x1a, 0xac, 0x42, 0xfc, 0x5c, 0xec, 0x89, 0xc9, 0xc9, 0xf9, 0xa5, 0x79, 0x25, 0x12,
    0x4c, 0x0a, 0x4c, 0x1a, 0x9c, 0x42, 0x02, 0x5c, 0x1c, 0x05, 0x89, 0xc5, 0xc5, 0xe5, 0xf9, 0x45,
    0x29, 0x12, 0xcc, 0x20, 0x11, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6d, 0x2b, 0xb1, 0x17, 0x5f,
    0x00, 0x00, 0x00,
}

把这个文件移动到你go项目的PBMessage文件夹下(或者你自己定义),不过此时我们的准备工作还没有完成。

在GOPATH目录执行命令:

go get github.com/golang/protobuf/proto

在你的项目的github目录下就会出现对应的支持protobuffer的go文件。

例子

这里我们举一个很简单的例子:

client:

    public void OnClickSend()
    {
        CG_LOGIN_IN pak = new CG_LOGIN_IN();
        pak.id = 1;
        pak.account = "ilovechina";
        pak.password = "root";
        byte[] bytes = CG_LOGIN_IN.SerializeToBytes(pak);
        m_Network.Send(bytes, 0, bytes.Length);
    }

在服务器:

package main

import (
    "net"
    "log"
    "fmt"
    "HttpServer/PBMessage"
    "github.com/golang/protobuf/proto"
)

const DefaultAddress = "localhost:8888"
const MaxByteCount = 1024 * 1024

func Welcome(conn net.Conn) {
    addr := conn.RemoteAddr()
    fmt.Printf("Welcome %v\n", addr)
}

func ReadByte(conn net.Conn) {

    buffer := make([]byte, MaxByteCount)
    for{
        nbytes, err := conn.Read(buffer)
        if err != nil {
            log.Fatalln(err)
        }

        if nbytes > 0 {
            fmt.Println(nbytes, string(buffer))
            msg := ProtobufPacket.CG_LOGIN_IN{}
            err = proto.Unmarshal(buffer, &msg)//解码
            if err != nil {
                log.Fatalln(err)
            }
            fmt.Printf("id : %v  account : %v passwrod : %v\n", *msg.Id, *msg.Account, *msg.Password)
        }
    }
}

func main() {

    listener, err := net.Listen("tcp", DefaultAddress)
    if err != nil {
        log.Fatalln(err)
    }

    for{
        connection, err := listener.Accept()
        if err != nil {
            log.Fatalln(err)
        }

        Welcome(connection)
        go ReadByte(connection)
    }

}

乍一看好像没有什么问题,但是如果你运行并且让服务器连接,你会发现服务器报错:
这里写图片描述
但是如果你无视这个错误,继续输出msg的值你会发现结果是对的,那么为什么会报这么一个错误呢?
原因在于切片buffer的长度,我们只需要解码的切片的长度应该是nbytes个,但是我们传给Unmarshal的buffer的长度是MaxBytesCount,所以这里只需要简单的修改为:

err = proto.Unmarshal(buffer[:nbytes], &msg)//仅解码我们需要的长度

这样运行就没有问题。

内容概要:本文介绍了一种基于多目标粒子群算法(MOPSO)的微电网优化调度模型,综合考虑风能、光伏、储能系统、柴油发电机、燃气轮机以及与主电网之间的能量交互等多种分布式能源的协同运行。通过构建以运行成本最小化、碳排放最低化和系统可靠性最优化为目标的多目标优化模型,利用Matlab平台实现MOPSO算法求解,完成对微电网在不同运行场景下的能量管理与调度方案优化。该模型能够有效平衡经济性与环保性之间的关系,适用于含多类型分布式电源的复杂微电网系统,具有较强的工程应用价值和科研参考意义; 适合人群:具备一定电力系统基础知识和Matlab编程能力的研究生、科研人员及工程技术人员,尤其适合从事微电网、智能电网、综合能源系统、可再生能源集成与优化调度等领域研究的专业人士; 使用场景及目标:①用于多能源耦合微电网系统的协同优化调度研究;②支持多目标智能优化算法在能源系统中的建模与求解实践,帮助用户掌握MOPSO在实际工程问题中的应用方法;③为学术论文复现、毕业设计、科研项目开发提供完整的代码实例与技术支撑; 阅读建议:建议读者结合Matlab代码与理论文档,深入理解目标函数构建、约束条件处理及Pareto最优解集生成机制,重点关注算法参数设置、多目标权衡分析与结果可视化,并可通过调整能源配置或引入新约束进行二次开发与创新研究。
内容概要:本文系统研究了基于模型预测控制(MPC)的滚动优化方法在微电网多时间尺度能量管理调度中的应用。通过构建包含风能、光伏、储能等多种分布式能源的微电网综合系统模型,充分利用MPC的前瞻性预测与滚动优化机制,实现对系统内部能量流的精细化、动态化调控。研究重点解决了新能源出力强不确定性带来的调度挑战,兼顾系统运行的经济性、稳定性与可靠性,在日前、日内及实时等多个时间尺度上实现了优化决策的协同。文中配套提供了完整的Python代码实现,涵盖模型构建、约束处理、目标函数设定与求解全过程,具有较强的可复现性与工程参考价值。; 适合人群:具备一定电力系统、优化理论基础和Python编程能力的研究生、科研人员及从事微电网、综合能源系统、能源互联网等领域研究的工程技术人员。; 使用场景及目标:①深入理解MPC在复杂能源系统调度中的核心原理与技术优势;②学习并复现多时间尺度滚动优化的完整建模与求解流程;③为微电网能量管理系统(EMS)的开发、相关学术研究或工程项目提供直接的算法实现参考与技术支撑; 阅读建议:建议读者结合所提供的Python代码进行逐行研读与调试,亲自动手修改系统参数、负荷曲线或新能源出力数据,以深刻体会MPC算法的动态响应特性与优化效果,进而在此基础上开展二次开发与创新性研究。
智能安防是依托人工智能、大数据、物联网等前沿技术构建的新一代安全防护体系,彻底打破了传统安防“被动监控、事后追溯”的局限。它不再是孤立的摄像头、门禁和报警器的简单组合,而是通过全域感知设备的互联互通,实现对人员、车辆、环境等多维度数据的实时采集与智能分析。从社区出入口的人脸无感通行、异常行为识别,到道路上的违章智能抓拍、重点区域的入侵预警,再到企业园区的消防隐患预判、设备故障自动告警,智能安防能在毫秒级完成风险研判,把安全防线从“事后处置”前移到“事前预防”。如今,它早已渗透到城市治理、居家生活、商业运营等各类场景,成为守护公共安全与私人空间的核心技术支撑。 不同于传统安防依赖人工盯守的高成本模式,智能安防凭借算法的持续迭代,不断拓展安全防护的边界。它可以通过对历史数据的深度挖掘,提前识别人群聚集、消防通道占用等潜在风险,联动公安、物业、应急等多部门快速响应,大幅降低安全事件的发生概率和处置时长。在老旧小区改造中,智能安防设备的加装解决了过去流动人口管理难、高空抛物溯源难等长期痛点;在家庭场景里,智能门锁、可视门铃、燃气泄漏报警器等设备组成的居家安防网络,让用户通过手机就能随时掌握家中安全状态。随着数字城市建设的推进,智能安防正从单一的安全工具,进化为构建智慧城市安全底座的关键组成部分,为人们的日常工作与生活筑牢更高效、更精准的防护屏障。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值