Protocol Buffer c++

最近小编负责游戏开发,游戏附带直播,直播的话已经有方案,可以关注小编的《ios直播》

上一篇小编主要写了cocos怎么搭建protocol buffer ,近期调试socket然后也没时间写文章。难得今天可以写点什么

如果按小编上一篇的操作,应该可以生成如下文件.h跟.cc,

1.png

*1.1你用记事本写一个

//简单的一个message 保存成xxx.proto
option optimize_for = LITE_RUNTIME;
message LogonReqMessage {
          required int64 acctID = 1;
          required string passwd = 2;      
}

*1.2用小编的方法生成 LogonReqMessage.h LogonReqMessage.cc文件

cba.png

1.3 PB主要是序列化跟反序列化的一个过程

void testSimpleMessage()
    {
        printf("==================This is simple message.================\n");
        //序列化LogonReqMessage对象到指定的内存区域。
        LogonReqMessage logonReq;
        logonReq.set_acctid(20);
        logonReq.set_passwd("Hello World");
        //提前获取对象序列化所占用的空间并进行一次性分配,从而避免多次分配
        //而造成的性能开销。通过该种方式,还可以将序列化后的数据进行加密。
        //之后再进行持久化,或是发送到远端。
        int length = logonReq.ByteSize();
        char* buf = new char[length];
        logonReq.SerializeToArray(buf,length);
        //从内存中读取并反序列化LogonReqMessage对象,同时将结果打印出来。
        LogonReqMessage logonReq2;
        logonReq2.ParseFromArray(buf,length);
        printf("acctID = %I64d, password = %s\n",logonReq2.acctid(),logonReq2.passwd().c_str());
    //用完之后delete ,释放内存
        delete [] but;
    }

2.1以上是最简单的PB,小编拿自己项目中的PB 给大家演示一下实际开发中怎么做

//进入房间响应
message RoomEnterMessage {
    optional string roomName = 1;//房间名
    optional int32 blindLimit = 2;//大盲注
    repeated PlayerDataMsg actorData = 3;//玩家数据
    repeated string communityCards = 4;//公共牌
    repeated int32 pot=5; //底池 与边池
    optional string videoUrl = 6;//视频地址
    repeated string cards = 7;//自己手牌
    optional string actorId = 8;//玩家自己ID
    optional string nickName=9;//自己昵称
    optional int32 userType=10;//用户类型
    
}
//玩家数据结构体 有玩家进入房间时对其他玩家推送 :command=1120
message PlayerDataMsg {
    optional string actorId = 1;
    optional string actorName =2;//昵称
    optional int32 location = 3;//位置
    optional PlayerGameData gameData =4;
}

//游戏玩家数据
message PlayerGameData {
    optional string actorId = 1;
    optional int64 totalAmount=2; //剩余总筹码
    optional int32 betAmount=3; //下注筹码
    optional int32 action=4; //操作  跟注、加注等
    optional int32 actionTime = 5;//操作时间
}


*2.2 老规矩生成.h .cc文件

opq.png
iop.png

*2.3 socket连接,发送你这边的内容

void HelloWorld::connectServer()
{
    //初始化
    socket.Init();
    socket.Create(AF_INET, SOCK_STREAM,0);
    
    //设置服务器的ip地址,端口号
    //并连接服务器 Connect
    const char *ip = "192.168.1.68";
    int port = 9090;
    //发送连接
    bool result = socket.Connect(ip, port);
//    Data();
//    Data *data = 0x7a1d;
    
    
    RoomEnterRequest room;
    room.set_sessionid("2");
    room.set_roomid(2);
    std::string str=room.SerializeAsString();
    
    int len =  room.SerializeAsString().length() + 2;
    
//    “序列化”(Serialization)
//    “反序列化” (Deserialization)
    
    
    PbDataModule* pb;
    char *buff = pb->getDataWith(len,8, str);
    int idx = 8;
    
    socket.Send(buff,idx+len-2);
    
    std::string roomStr = room.SerializeAsString();
   
    //发送数据Send
    socket.Send(roomStr.c_str(), 5);
    
    if (result) {
        CCLOG("connect to server success!");
        //开启新线程,在子线程中,接收数据
        std::thread recvThread = std::thread(&HelloWorld::receiveData,this);
        recvThread.detach();//从主线程分离
    }else{
        CCLOG("can not connect to server");
        return;
    }

}

注意:RoomEnterRequest room这是我这边socket请求的pb,这中间有序列化得过程我把代码贴出来,

char* PbDataModule::getDataWith(int len,int cout,std::string roomStr)
{
//这是我们项目定义好的,如果读者序列化有问题可以咨询下小编,这一块底层要求要扎实

/*
序列化过程
*/
    unsigned char h[cout],*p;//先用一个容器,这个容器将存你请求socket字节流
    int  idx = 0;//第一位是0
    h[idx++]= 0x7a;//第二位7a
    h[idx++] = 0x1d;//第三位1d
    
    p = (unsigned char*)&len;
    h[idx++] = p[3];
    h[idx++] = p[2];
    h[idx++] = p[1];
    h[idx++] = p[0];
    
    
    h[idx++] = 0x04;//第七位04
    h[idx++] = 0x56;//第八位56
    
    
    char* buff = new char[idx + len -2];
    memcpy(buff,h,idx);
    memcpy(buff+idx,roomStr.c_str(),len-2);
    
    return buff;
    
    delete [] buff;//用完之后释放内存
}

*3.1前面一块就是socket请求,后面就是socket接收消息,解析PB的过程,小编全程注释

void HelloWorld::receiveData()
{
    //因为是强联网
    //所以可以一直检测服务端是否有数据传来
    while (true) {
        //接收数据 recv
        char data[512] = "";
        
        int result = socket.Recv(data, 512,0);
        
        printf("result,%d\n",result);
        //这里打印出来的接收的二进制流(data)总共是124个字节
        
        //与服务器的连接断开了
        if (result <= 0) {
            break;
            
        }
/*
反序列化过程
*/
        //将二进制的头,错误,还有长度用数组提取出来
        char chhead[2];
        char chlen[4];
        char chcmdcode[2];
        char cherrorcode[2];
        
       //data总共是124个字节
        //下面是取得过程
        //它的前两个字节,0、1是头
        memcpy(chhead, data, sizeof(chhead));
        //它的字节是长度是4个字节 从data的第2位之后开始取
        memcpy(chlen, data+2, sizeof(chlen));
        //它的字节是长度是2个字节 从data的第6位之后开始取
        memcpy(chcmdcode, data+6, sizeof(chcmdcode));
        //它的字节是长度是2个字节 从data的第8位之后开始取
        memcpy(cherrorcode, data+8, sizeof(cherrorcode));
        
        //剩下的字节就是pb的二进制流,从第十位开始取,那么只要result(总字节长度)-10
        char *pdata = new char[result-10];
        memcpy(pdata, data+10, result-10);//从第十个字节开始拷贝到 到pdata里面去
        
        RoomEnterMessage msgOut;
        //解析该字符串
        //问题出现在这里了。当把char*传入ParseFromString时,会把char*转换成string类型,会在第一个'\0'的地方,把这个缓冲区给截断,问题就出现在这里了。
        std::string strData(pdata,result-10);
        
        if (msgOut.ParseFromString(strData)) {
            //解析该字符串
            CCLOG("房间名:%s  大盲注:%d",msgOut.roomname().c_str(),msgOut.blindlimit());
            CCLOG("自己昵称%s 玩家自己ID%s  ",msgOut.nickname().c_str(),msgOut.actorid().c_str());
           // CCLOG("0:%s   1:%s",msgOut.cards(0).c_str(),msgOut.cards(1).c_str());
             //将socket返回的存入到单例当中
            Global::shareGlobal()->setRoomName(msgOut.roomname());
            Global::shareGlobal()->setBlindLimit(msgOut.blindlimit());
            Global::shareGlobal()->setActorId(msgOut.actorid());
            Global::shareGlobal()->setNickName(msgOut.nickname());
            //取出嵌套的PlayerDataMsg
            google::protobuf::RepeatedPtrField<PlayerDataMsg>* dateMsg = msgOut.mutable_actordata();
            google::protobuf::RepeatedPtrField<PlayerDataMsg>::iterator it = dateMsg->begin();
            
            for (; it != dateMsg->end(); ++it) {
                
                CCLOG("actorId:%s  actorName:%s  location:%d  ",it->actorid().c_str(),it->actorname().c_str(),it->location());
                //存入单例当中
                PDataMsg::getInstance()->setActorId(it->actorid());
                PDataMsg::getInstance()->setActorName(it->actorname());
                PDataMsg::getInstance()->setLocation(it->location());
                
                CCLOG("下注筹码:%d",it->gamedata().betamount());
                
//                CCLOG("剩余总筹码:%d",it->gamedata().totalAmount());
                
                CCLOG("操作  跟注、加注等:%d",it->gamedata().action());
                 //存入单例当中
                PGameData::getInstance()->setBetAmount(it->gamedata().betamount());
                PGameData::getInstance()->setAction(it->gamedata().action());
                
                
            }
            
            
            
        }
        
        auto scene = StartScene::createScene();
        auto tt = TransitionFade::create(1.0f, scene);
//        Director::getInstance()->replaceScene(tt);
        
        delete []pdata;
        
    }
    
    
    //关闭连接
    socket.Close();
}


如果小编讲的比较模糊,看不懂什么意思,那就惆怅了,惭愧了。

有问题留言吧,大家一起学习,

如果喜欢就点个赞哦!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,900评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,644评论 18 139
  • 一个别人人格型的我,不知道你是不是。 我们总是别人的,除了睡觉的时候,你能独立,你还能抽出点时间给过自己吗? 好像...
    光芒万丈小飞侠阅读 165评论 0 1
  • 小猴的美好时光阅读 171评论 0 2
  • 82 /寻找100首歌系列 普通人在时代中往往是没有选择的,特别是在动荡的时代,就像我们看过的电影《滚滚红尘》,《...
    达耳闻阅读 2,244评论 1 9