【protobuf 2的使用】0.gitbash终端 1.pb在vscode中的的格式化和跳转 2.服务器:netty 3.客户端:creator 4.自定义Option(如添加msgid)

-----pb和代码格式化

1.先下载llvm。 如: LLVM-12.0.0-6923b0a7-win64.exe

Release LLVM 17.0.6 · llvm/llvm-project (github.com)

2.安装2个插件 // pb高亮 和 跳转

3.修改vscode下的setting.json文件,设置保存时格式化代码 // 当然还有终端为gitbash

或者File->Preferences->Settings下修改setting.json // 点击文件时可以在ide中定位

{
    "git.openRepositoryInParentFolders": "never",
    // 保存时触发clang格式化
    "editor.formatOnSave": true,
    "window.openFilesInNewWindow": "on",
    "explorer.autoReveal": "focusNoScroll",
    "explorer.confirmDelete": false,
    // 使用clang-format
    "[proto3]": {
        "editor.defaultFormatter": "xaver.clang-format"
    },
    "workbench.iconTheme": "vs-minimal",
    "workbench.colorTheme": "Visual Studio Light",
    "window.confirmSaveUntitledWorkspace": false,
    "terminal.integrated.profiles.windows": {
        "Git Bash": {
            "path": "F:\\Git\\git-bash.exe",
            // "path": "C:\\Program Files\\Git\\bin\\bash.exe",
            "args": []
        }
    },
    "terminal.integrated.defaultProfile.windows": "Git Bash"
}

4.配置下 .clang.format   // 注意不要改下面}的位置

{BasedOnStyle: Google, 
AlignConsecutiveDeclarations: true, 
AlignConsecutiveAssignments: true, 
ColumnLimit: 0, 
IndentWidth: 4}

5.设置格式化为clang.format // 由于clang已经在安装时在path环境变量中了,因此无需再配置。

右键-->Format Document With..-->Configure Default Formatter...-->Clang Format

---------------------------------------------------------------------------

autoGen.sh

rm -rf out
mkdir out

# Java
protoc.exe --java_out=./out ./*.proto


# cocos
# pbjs -t static-module -w commonjs --es6 --keep-case --root comm -o ./out/login.js ./login.proto
# pbts -o ./out/login.d.ts ./out/login.js

echo "finish"

login.proto

syntax = "proto2";

package msg;
option java_package = "org.mj.bizserver.allmsg";

message CSLogin {
    // 消息 Id
    optional int32 msgId = 1;
}

----------------------20221227(思考proto文件的组织)-----------------

其实,我现在认为,作为工具的话,

common.proto  // 定义的一些 Dxx类。模块之间是不会相互引用的。

101_200_mail.proto

201_300_friend.proto

这样子也没什么问题,在写工具类生成代码时,先生成临时文件,再进一步生成。

但实际上,是不够直观,也可以直接在proto文件中,指定导出的类名什么的,这种稍微看着别扭一点,但是实际也没什么问题,这样子写工具类简单了,无需中间文件。

-----------------20221101(在cocos creator中使用生成对应的.d.ts,使用typescript时有协议提示)----------------------

 1.威海麻将中,安装下这个,就在本地得到node_modules

npm install --save-dev protobufjs@6.8.8

2.将protoc.exe和pbjs、pbts添加到环境变量中

// proto.exe
F:\pb

// pbjs 和 pbts 这2个node.js写的脚本
F:\pb\node_modules\.bin

3.autoGen.cmd

@echo off

rd /s/q .\out
md .\out

rem # Java
protoc --java_out=.\out .\commProtocol.proto
protoc --java_out=.\out .\passportServerProtocol.proto
protoc --java_out=.\out .\hallServerProtocol.proto
protoc --java_out=.\out .\MJ_weihai_Protocol.proto
protoc --java_out=.\out .\clubServerProtocol.proto
protoc --java_out=.\out .\chatServerProtocol.proto
protoc --java_out=.\out .\recordServerProtocol.proto

rem # JS
rem # 第二条命令可能不被执行,
rem # 直接复制粘贴到 DOS 命令行手动执行解决上面这个问题
set "_pbjs=node %NODE_HOME%\node_modules\protobufjs\bin\pbjs"
set "_pbts=node %NODE_HOME%\node_modules\protobufjs\bin\pbts"

%_pbjs% -t static-module -w commonjs --es6 --keep-case --root comm -o .\out\mod_commProtocol.js .\commProtocol.proto
%_pbts% -o .\out\mod_commProtocol.d.ts .\out\mod_commProtocol.js

%_pbjs% -t static-module -w commonjs --es6 --keep-case --root passportServer -o .\out\mod_passportServerProtocol.js .\passportServerProtocol.proto
%_pbts% -o .\out\mod_passportServerProtocol.d.ts .\out\mod_passportServerProtocol.js

%_pbjs% -t static-module -w commonjs --es6 --keep-case --root hallServer -o .\out\mod_hallServerProtocol.js .\hallServerProtocol.proto
%_pbts% -o .\out\mod_hallServerProtocol.d.ts .\out\mod_hallServerProtocol.js

%_pbjs% -t static-module -w commonjs --es6 --keep-case --root MJ_weihai_ -o .\out\mod_MJ_weihai_Protocol.js .\MJ_weihai_Protocol.proto
%_pbts% -o .\out\mod_MJ_weihai_Protocol.d.ts .\out\mod_MJ_weihai_Protocol.js

%_pbjs% -t static-module -w commonjs --es6 --keep-case --root clubServer -o .\out\mod_clubServerProtocol.js .\clubServerProtocol.proto
%_pbts% -o .\out\mod_clubServerProtocol.d.ts .\out\mod_clubServerProtocol.js

%_pbjs% -t static-module -w commonjs --es6 --keep-case --root chatServer -o .\out\mod_chatServerProtocol.js .\chatServerProtocol.proto
%_pbts% -o .\out\mod_chatServerProtocol.d.ts .\out\mod_chatServerProtocol.js

%_pbjs% -t static-module -w commonjs --es6 --keep-case --root recordServer -o .\out\mod_recordServerProtocol.js .\recordServerProtocol.proto
%_pbts% -o .\out\mod_recordServerProtocol.d.ts .\out\mod_recordServerProtocol.js

pause

4.这样子在当前目录下,生成mod_xxx.js和mod_xxx.d.ts

5.由于在proto文件中直接写的有syntax、package、option java_package,因此直接就生成的有java的。

syntax = "proto3";

package msg;
option java_package = "org.mj.bizserver.allmsg";

// 
// 聊天服务器消息编号
enum ChatServerMsgCodeDef {
    _Dummy = 0;
    _SendQuickMsgCmd = 401;
    _SendQuickMsgResult = 402;
    _SendQuickMsgBroadcast = 403;
    _SendEmojiCmd = 404;
    _SendEmojiResult = 405;
    _SendEmojiBroadcast = 406;
};

//
// 发送快速消息
///
// 指令
message SendQuickMsgCmd {
    // 消息 Id
    sint32 msgId = 1;
}

// 结果
message SendQuickMsgResult {
    // 消息 Id
    sint32 msgId = 1;
    // 是否发送成功
    bool ok = 2;
}

// 广播
message SendQuickMsgBroadcast {
    // 消息来自用户 Id
    sint32 fromUserId = 1;
    // 消息 Id
    sint32 msgId = 2;
    // 是否发送成功
    bool ok = 3;
}

//
// 发送表情
///
// 指令
message SendEmojiCmd {
    // 表情 Id
    sint32 emojiId = 1;
}

// 结果
message SendEmojiResult {
    // 表情 Id
    sint32 emojiId = 1;
    // 是否发送成功
    bool ok = 2;
}

// 广播
message SendEmojiBroadcast {
    // 消息来自用户 Id
    sint32 fromUserId = 1;
    // 表情 Id
    sint32 emojiId = 2;
    // 是否发送成功
    bool ok = 3;
}

-------------------------------------------之前写的服务器和客户端--------------------------------------

【服务器】java中使用protobuf 1.protoc.exe下载 2.build.sh编译脚本 3.vscode安装插件编辑game.proto(文件有颜色提示)

1)以windows为例子,将以下地址粘贴到浏览器下载64位的zip包,解压出proto.exe文件(各种语言都用这个编译脚本)

https://github.com/protocolbuffers/protobuf/releases/download/v3.14.0/protoc-3.14.0-win64.zip

 github官网下载如下

2)pom.xml

<dependency>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-java</artifactId>
     <version>3.10.0-rc-1</version>
</dependency>

3)在vscode下载插件写协议文件,有一定的语法着色

4)编译脚本build.sh(1.发现写成build.bat反而不行,改为sh则可以执行双击运行,直接生成msg下的文件!2.read命令阻塞那查看编译完成)

win版本build.sh例子(从proto.exe所在路径开始写相对路径,客户端只用关注protocol目录里面的相关的业务proto文件即可)

# 清空下之前的协议文件
rm -rf ./../src/main/java/org/example/msg
# 生成新文件
./protoc.exe  ./protocol/*.proto ./options/*.proto --java_out=./../src/main/java
# 删除google生成的多余的文件
rm -rf ./../src/main/java/com

echo "编译完毕!"
read var

5)目录结构

idea中目录结构(只用关注protocol下的proto文件即可)

options.proto ( 自定义扩展,其中descriptor.proto自己从之前下载的proto工具中找到即可)

syntax= "proto2";
// 导出包名
option java_package="org.example.msg";

import "options/descriptor.proto";

extend google.protobuf.MessageOptions{
	optional int32 msgid = 10001;
}

101_200_login.proto

syntax = "proto2";
option java_package = "org.example.msg";
// 导出类名
option java_outer_classname = "MsgLogin";

message DHuman {
  optional string userName = 1;  // 用户名
  optional string password = 2;  // 密码
}

202_300_game.proto

syntax = "proto2";
option java_package = "org.example.msg";
// 导出类名
option java_outer_classname = "MsgGame";

// 引入其它proto文件,以使用DLogin(其实这里不应该出现这种一个模块引入另一个模块的写法
// 公共的东西只应该有Dxxx这种公用数据,应该定义在common.proto文件中)
import "protocol/101_200_login.proto";

import "options/options.proto";

// 开始战斗
message CSStartBattle {
  option (msgid) = 101;
  optional DHuman info = 1;
}

message SCStartBattle {
  optional EStatus status = 1;  // 开始状态
}

enum EStatus{
  OK = 1;
  FAIL = 2;
}

Main.java(注意下获取msgid的方式)

package org.example;

import com.google.protobuf.GeneratedMessageV3;
import org.example.msg.MsgGame;
import org.example.msg.MsgLogin;
import org.example.msg.Options;


public class Main {
    public static void main(String[] args) throws Exception {
        MsgGame.CSStartBattle.Builder builder = MsgGame.CSStartBattle.newBuilder();
        builder.setInfo(MsgLogin.DHuman.newBuilder().setUserName("jianan").setPassword("123456").build());

        // 获取里面自定义的msgid
        Class<?>[] innerClazzArray = MsgGame.class.getDeclaredClasses();
        for (Class<?> innerClazz : innerClazzArray) {
            if (!GeneratedMessageV3.class.isAssignableFrom(innerClazz)) {
                continue;
            }

            GeneratedMessageV3 returnObj = (GeneratedMessageV3) innerClazz.getDeclaredMethod("getDefaultInstance").invoke(innerClazz);

            // 默认是0
            int msgId = returnObj.getDescriptorForType().getOptions().getExtension(Options.msgid);
            if (msgId != 0) {
                System.out.println("msgid:" + msgId);

                // 存储自定义消息id与消息的映射关系
            }
        }

        // 得到消息号
        int msgCode = builder.build().getDescriptorForType().getOptions().getExtension(Options.msgid);
        // 编码为字节码
        byte[] bytes = builder.build().toByteArray();

        System.out.println("msgCode:" + msgCode);
        System.out.println(bytes);
    }
}

/*
msgid:101
msgCode:101
[B@5e57643e
 */

【客户端】 creator中使用protobuf: 1.需要导入pb为插件 2.使用protobuf.min.js 3.命令号enum的获取

 1)下载地址 

https://github.com/protobufjs/protobuf.js/tree/master/dist

 2)game.proto

// awesome.proto
package awesomepackage;
syntax = "proto3";
 
enum Cmd{
    INVALID_CMD = 0;
    AwesomeMessage = 1;
}
 
message AwesomeMessage {
    string awesome_field = 1; // becomes awesomeField
}

3)creator 1.9.1

cc.loader.loadRes("awesome.proto", function (err, data) {
            if (err) {
                return;
            }
 
            // 读到文本内容,解析为pb脚本
            let pb = protobuf.parse(data);
 
            // 获取类型
            var AwesomeMessage = pb.root.lookupType("AwesomeMessage");
 
            // 构造消息
            var payload = {awesomeField: "AwesomeString"};
 
            // json编码
            console.log("字符串长度:", JSON.stringify(payload).length);
 
            // pb编码
            var message = AwesomeMessage.create(payload);
            var buffer = AwesomeMessage.encode(message).finish();
            console.log("pb后长度:", buffer.length);
 
            // 解码
            var message = AwesomeMessage.decode(buffer);
            console.log(message);
 
            // 通过枚举输出命令号
            let Cmd = pb.root.lookupEnum("Cmd").values;
            console.log(Cmd.AwesomeMessage);
});

注意: 文档中只有node,js的加载用法, creator中读取资源要用自己的方法。

----------------------

由于导入为插件了,不需要require protobuf的东西直接通过protobuf.xxx即可引用


       // var ProtoBuf = require('protobufjs');
       var builder =   protobuf.parse("syntax = \"proto3\";  \npackage yd;\n\nmessage data{\nstring y = 1;\nstring d = 2;\n}");


        if(typeof(cc.TONGXIN) == "undefined"){
            cc.TONGXIN = {
                // AwesomeMessage : builder.build("yd"),
                AwesomeMessage : builder.valueOf("yd"),
                wslink :"ws://127.0.0.1:8889/Ws",
      
                jishi: 0, //计数
                yeschushi:false,// 是否初始化
                timeout:8000, //80秒没连接推出
                restart:200,// 2秒重练一次
                run:0.01, //执行间隔
                wsdata:Array(),//队列数据
                isliank:false//是否连接
            };
        }
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在C语言发送XML格式的数据,可以使用Socket编程的send()函数。send()函数可以将指定长度的数据发送到已连接的套接字: ```c send(socket, xml_data, strlen(xml_data), 0); ``` 其,xml_data是一个包含XML数据的字符串指针。 如果你想要在C语言使用protobuf来序列化和反序列化数据,你需要先定义一个.proto文件来描述你的数据结构。然后,使用protobuf的编译器将.proto文件编译成C语言代码,并将其包含到你的项目。 一旦你有了protobuf生成的C语言代码,你就可以使用它来序列化和反序列化你的数据。以下是一个使用protobuf的例子: ```c // 序列化数据 YourProtoMessage message; char buffer[MAX_BUFFER_SIZE]; message.value1 = 123; message.value2 = "Hello, world!"; size_t size = YourProtoMessage_serialize(&message, buffer, MAX_BUFFER_SIZE); // 发送数据 send(socket, buffer, size, 0); // 接收数据 char recv_buffer[MAX_BUFFER_SIZE]; size_t recv_size = recv(socket, recv_buffer, MAX_BUFFER_SIZE, 0); // 反序列化数据 YourProtoMessage received_message; YourProtoMessage_deserialize(&received_message, recv_buffer, recv_size); ``` 以上代码,YourProtoMessage是你在.proto文件定义的数据结构。YourProtoMessage_serialize()和YourProtoMessage_deserialize()是protobuf自动生成的函数,用于序列化和反序列化数据。MAX_BUFFER_SIZE是你定义的缓冲区大小,用于存储序列化后的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值