zoukankan      html  css  js  c++  java
  • 使用Protobuf定义网络协议

    准备工具:

    工具下载地址如下:https://github.com/protocolbuffers/protobuf/releases/tag/v3.6.1,主要使用到的文件有:

    protoc.exe工具:通过此工具将从自定义的协议文件(.proto)得到相应(.java)的Java类文件;
    对应proto.exe版本的protobuf-java.jar包,用于解析上面得到的.java类,这里我使用的是2.5.0版本的protobuf;
    chat_send.proto协议文件,关于proto协议文件的书写语法详细的可以查看:Protobuf语言指南,chat_send.proto内容如下(包名package可以根据当前服务器应用的包名进行修改):

    //定义使用的protobuf版本
    syntax = "proto2";
    //定义所在的protobuf包空间
    package  ares.logic.msg.proto;
    
    //生成的java类所在的包路径
    option java_package = "ares.logic.msg.proto";
    //生成的java类的类名
    option java_outer_classname = "ChatSendMsg";
    
    //声明一个message类
    message ChatSend{ //(5)
        optional int32 mid = 1;   // 消息ID, 非必要
        required int64 playerid = 3;  // 游戏角色ID 必要
        required int32 userid = 4;  // 用户ID, 必要
        required int32 power = 5; // 角色战力值(如果没有可设置为角色等级)
        required int32 channel = 6;  //消息频道 必要
        required string content = 7;  //聊天内容 必要
        required string playername = 8; // 游戏昵称 必要
        required int32 zeusid = 9; // 区服ID 必要
        required string ip = 10; // 当前发言人的IP 必要
        optional int32 banned = 11; // 是否禁言
    

     cs_enum.proto协议类型枚举文件,用于列举所有协议数据结构的编号:

    syntax = "proto2";
    //定义所在的protobuf包空间
    package  ares.logic.msg.proto;
    
    //生成的java类所在的包路径
    option java_package = "ares.logic.msg.proto";
    //生成的java类的类名
    option java_outer_classname = "EnmMsgId";
    
    enum EnmCmdId
    {
        UNIVERSAL = 0;
        ChatSend = 1001;//登录请求协议号
    }
    

     将.proto转化为Java类文件的处理脚本,这里其实只是一句命令行指令:

    protoc  chat_send.proto --java_out=../src/
    

     这里我根据实际项目目录结构定义了一个转文件的.bat批处理文件:

    echo on
    call protoc --version
    
    call protoc  chat_send.proto --java_out=../src/
    call protoc  cs_enum.proto --java_out=../src/
    PAUSE
    

     protobuf数据通信过程:

    1.客户端创建数据:

    要构建一个protobuf数据,需要通过对应协议文件的数据结构,先通过每个数据类型的newBuilder()方法来创建对应的Builder对象,再对Builder中的属性进行赋值,最后才能使用Builder来build()数据对象

    public ChatSend getProtobuf() {
         ChatSend.Builder chatBuilder = ChatSend.newBuilder();
          chatBuilder.setMid(EnmCmdId.ChatSend.getNumber());
    	chatBuilder.setPlayerid(roleId);
    	chatBuilder.setBanned(banned);
    	chatBuilder.setChannel(channel);
    	chatBuilder.setContent(content);
    	chatBuilder.setIp(loginIp);
    	chatBuilder.setPlayername(roleName);
    	chatBuilder.setPower(level);
    	chatBuilder.setUserid(userId);
    	chatBuilder.setZeusid(serverId);
    	return chatBuilder.build();
    	}
    

     客户端单独启用一个线程,将请求的消息发送给服务器

    private void initThread() {
    		BlockingThreadPool.createThreads(BlockingThreadPool.SkyEye_CHECKER, 1, new SocketHandler());
    	}
    
    	private class SocketHandler implements BlockingThreadPool.Callbacker<SkyEyeMsg> {
    		private boolean retry;
    		@Override
    		public void callback(SkyEyeMsg info) {
    			byte[] data = info.getProtobuf().toByteArray();
    			try {
    				if (socket == null) {
    					initSocket();
    				}
    				byte[] len = intToByteArray(data.length);
    				socket.getOutputStream().write(HEAD);
    				socket.getOutputStream().write(len);
    				socket.getOutputStream().write(data);
    			} catch (Exception e) {
    				closeSocket(); //socket重连
    				if(retry){
    					SkyEyeChecker.logger.error("ckeckMsg Exception :" + e);
    				}else{
    					retry = true;
    					callback(info);
    					retry = false;
    				}
    			}
    		}
    
    		byte[] intToByteArray(int len) {
    			byte[] data = new byte[4];
    			data[0] = (byte) (len >> 24);
    			data[1] = (byte) (len >> 16);
    			data[2] = (byte) (len >> 8);
    			data[3] = (byte) len;
    			return data;
    		}
    	}
    
  • 相关阅读:
    oracle nvl,to_char 函数(二)
    GridView的使用技巧
    asp.net应用程序性能的提高方案
    浅谈 ViewState
    最为关心的问题,hbase查询一条数据的过程.
    HBase的弊端。
    拙建:(mapreduce 如何来分步统计词频)
    终于找到hbase分布式存储数据的方式.
    迷局一般的openjdk6jdk!
    IT事业不好走,大家在虚拟的世界,记得回到真实的世界,不然你将会成为下一个张孝祥.
  • 原文地址:https://www.cnblogs.com/cherish010/p/9871291.html
Copyright © 2011-2022 走看看