当前位置: 首页 > wzjs >正文

装潢公司网站源码php推广网站最有效办法

装潢公司网站源码php,推广网站最有效办法,小型网站有哪些,网站建设方法笔者前面博文Go语言网络游戏服务器模块化编程介绍了Go语言在开发网络游戏时如何进行模块化编程,在其中使用了Protobuf进行网络通信。在Protobuf官方实现中并没有生成C语言的实现,不过有一个开源的protobuf-c可以使用。 先来看看protobuf-c生成的代码&am…

笔者前面博文Go语言网络游戏服务器模块化编程介绍了Go语言在开发网络游戏时如何进行模块化编程,在其中使用了Protobuf进行网络通信。在Protobuf官方实现中并没有生成C语言的实现,不过有一个开源的protobuf-c可以使用。

先来看看protobuf-c生成的代码,假如如下PB:

syntax = "proto3";
package netmsg;enum NetCmdID
{CmdNone 	= 0;Ping 		= 1;Pong 		= 2;
}message PingPong
{uint32 time = 1;
}

生成的C代码类似这样:

typedef struct Netmsg__PingPong Netmsg__PingPong;struct  Netmsg__PingPong
{ProtobufCMessage base;uint32_t time;
};
#define NETMSG__PING_PONG__INIT \{ PROTOBUF_C_MESSAGE_INIT (&netmsg__ping_pong__descriptor) \
, 0 }/* Netmsg__PingPong methods */
void   netmsg__ping_pong__init(Netmsg__PingPong         *message);
size_t netmsg__ping_pong__get_packed_size(const Netmsg__PingPong   *message);
size_t netmsg__ping_pong__pack(const Netmsg__PingPong   *message,uint8_t             *out);
size_t netmsg__ping_pong__pack_to_buffer(const Netmsg__PingPong   *message,ProtobufCBuffer     *buffer);
Netmsg__PingPong *netmsg__ping_pong__unpack(ProtobufCAllocator  *allocator,size_t               len,const uint8_t       *data);
void   netmsg__ping_pong__free_unpacked(Netmsg__PingPong *message,ProtobufCAllocator *allocator);extern const ProtobufCMessageDescriptor netmsg__ping_pong__descriptor;

可以看到,PingPong在生成的C代码中结构是原样输出的,而函数中又是以C风格ping_pong输出的;同时包名netmsg在结构中首字母是大写,而在函数中又是全部小写

如果要解析PB,它提供了一个API:

PROTOBUF_C__API
ProtobufCMessage *
protobuf_c_message_unpack(const ProtobufCMessageDescriptor *descriptor,ProtobufCAllocator *allocator,size_t len,const uint8_t *data);

这里需要传入PB的描述符结构ProtobufCMessageDescriptor *,针对PingPong消息即netmsg__ping_pong__descriptor的地址。调用后会返回一个ProtobufCMessage *,只需要强转成Netmsg__PingPong*即可。这个返回值在使用完后需要调用函数protobuf_c_message_free_unpacked释放内存:

PROTOBUF_C__API
void
protobuf_c_message_free_unpacked(ProtobufCMessage *message,ProtobufCAllocator *allocator);

笔者想要的理想情况是与前面博文Go语言网络游戏服务器模块化编程中的一样,可以在网络消息处理函数中直接写需要处理的具体的PB消息。

在处理它时,直接在参数中写生成的C结构指针:

void onPing(user *u, Netmsg__PingPong *pb) {
}

直接使用一个宏DEFINE_HANDLER来映射网络消息ID与处理函数之间的关系,比如这样写:

DEFINE_HANDLER(Ping, PingPong, ping_pong);

宏的第一个参数是消息ID,第二个参数是C结构的写法,第三个参数是函数以及描述符的写法。

为了方便我们只写一次映射关系,DEFINE_HANDLER宏有两个实现,一个是作处理函数的注册用,另一个是实现网络消息的解析并调用自定义的处理函数。

  1. DEFINE_HANDLER宏作为处理函数注册用

DEFINE_HANDLER宏调用自定义函数regNetMsg来注册消息处理函数:

typedef void (*fnCB)(user *u, char *buf, uint32_t len);
static void regNetMsg(Netmsg__NetCmdID cmd, fnCB cb);
#define DEFINE_HANDLER(NetCmdID, PbStructType, PbDescType)                     \extern void on_##PbStructType(user *u, char *buf, uint32_t len);             \regNetMsg(NETMSG__NET_CMD_ID__##NetCmdID, on_##PbStructType);
  1. DEFINE_HANDLER宏实现网络消息的解析并调用自定义的处理函数

DEFINE_HANDLER宏内依次调用protobuf_c_message_unpack,自定义的消息处理函数,protobuf_c_message_free_unpacked即可:

#define DEFINE_HANDLER(NetCmdID, pbStructType, pbDescType) \
void on_##pbStructType(user *u, char *buf, uint32_t len) {\
Netmsg__##pbStructType* pb = \
protobuf_c_message_unpack(&netmsg__##pbDescType##__descriptor,\
len - sizeof(uint16_t), (const uint8_t *)&buf[sizeof(uint16_t)]);\
extern void on##NetCmdID(user *u, Netmsg__##pbStructType *pb);\
on##NetCmdID(u, pb); \
protobuf_c_message_free_unpacked((ProtobufCMessage *)pb, nullptr);

同一个宏如何实现两个功能?

假定我们的映射代码为net_msg.h

DEFINE_HANDLER(Ping, PingPong, ping_pong);

DEFINE_HANDLER的实现为reg_msg.h,在其中使用一个宏来判断一下是第一种功能还是第二种功能,在调用前定义功能宏:

#define DEF_FUNC
#include "reg_msg.h"

这样就可以实现只需要写一份映射代码,然后写处理函数的简便操作。但是这里有一点缺憾就是DEFINE_HANDLER宏因为protobuf-c生成的代码风格的缘故需要写两个,一个是结构的写法PingPong, 一个是函数以及描述符的写法ping_pong,而且包名的大小写也不一致。其实要解决这个问题非常简单,只需要在生成结构时代码时,添加一个typedef即可,比如PingPong,添加一个typedef struct Netmsg__PingPong netmsg__ping_pong;即可统一写成DEFINE_HANDLER(Ping, ping_pong);

typedef struct Netmsg__PingPong Netmsg__PingPong;
typedef struct Netmsg__PingPong netmsg__ping_pong;

我曾经给官方提过一个issue,希望能添加,但官方未响应。可以自行修改代码:

void MessageGenerator::
GenerateStructTypedef(google::protobuf::io::Printer* printer) {printer->Print("typedef struct $classname$ $classname$;\n","classname", FullNameToC(descriptor_->full_name(), descriptor_->file()));for (int i = 0; i < descriptor_->nested_type_count(); i++) {nested_generators_[i]->GenerateStructTypedef(printer);}
}

为:

void MessageGenerator::
GenerateStructTypedef(google::protobuf::io::Printer* printer) {printer->Print("typedef struct $classname$ $classname$;\n","classname", FullNameToC(descriptor_->full_name(), descriptor_->file()));printer->Print("typedef struct $classname$ ","classname", FullNameToC(descriptor_->full_name(), descriptor_->file()));printer->Print("$lcclassname$;\n","lcclassname", FullNameToLower(descriptor_->full_name(), descriptor_->file()));for (int i = 0; i < descriptor_->nested_type_count(); i++) {nested_generators_[i]->GenerateStructTypedef(printer);}
}

然后使用修改过的protoc-gen-c来编译PB。

下面给出完成的reg_msg.h代码,支持GCC和Clang编译器:

#ifdef USE_REG
#undef USE_REG#define HANDLER_BODY(NetCmdID, PbStructType)                                   \netmsg__##PbStructType *pb =                                                 \(netmsg__##PbStructType *)protobuf_c_message_unpack(                     \&netmsg__##PbStructType##__descriptor, nullptr,                      \len - sizeof(uint16_t), (const uint8_t *)&buf[sizeof(uint16_t)]);    \extern void on##NetCmdID(user *u, netmsg__##PbStructType *pb);               \on##NetCmdID(u, pb);                                                         \protobuf_c_message_free_unpacked((ProtobufCMessage *)pb, nullptr);#ifdef __clang__
#define DEFINE_HANDLER(NetCmdID, PbStructType)                                 \static void (^on_##PbStructType)(user * u, char *buf, uint32_t len) =        \^void(user * u, char *buf, uint32_t len) {                               \HANDLER_BODY(NetCmdID, PbStructType)                                   \};                                                                       \regNetMsg(NETMSG__NET_CMD_ID__##NetCmdID, on_##PbStructType);
#else
#ifdef DEF_FUNC
#define DEFINE_HANDLER(NetCmdID, PbStructType)                                 \void on_##PbStructType(user *u, char *buf, uint32_t len) {                   \HANDLER_BODY(NetCmdID, PbStructType)                                       \}
#elif defined(REG_MSG)
#undef DEFINE_HANDLER
#define DEFINE_HANDLER(NetCmdID, PbStructType)                                 \extern void on_##PbStructType(user *u, char *buf, uint32_t len);             \regNetMsg(NETMSG__NET_CMD_ID__##NetCmdID, on_##PbStructType);
#endif
#endif#include "net_msg.h"#endif

调用:

static swiss_map_t *mapNetMsg = nullptr;#ifdef __clang__
#ifdef _WIN32
void *const __imp__NSConcreteGlobalBlock[32] = {nullptr};
void *const __imp__NSConcreteStackBlock[32]	 = {nullptr};
#else
void *const _NSConcreteGlobalBlock[32] = {nullptr};
void *const _NSConcreteStackBlock[32]	 = {nullptr};
#endif
// 这里必须使用Clang的块语法
typedef void (^fnCB)(user *u, char *buf, uint32_t len);
#else
typedef void (*fnCB)(user *u, char *buf, uint32_t len);
#endifstatic void regNetMsg(Netmsg__NetCmdID cmd, fnCB cb) {swiss_map_insert(mapNetMsg, &cmd, (void *)&cb);
}// 由于GCC不支持静态嵌套函数,所以需要将解析消息的函数定义与消息的注册分开
// 而clang支持block语法,可以使用它写一个静态函数,可以直接在一起写
#if !defined(__clang__) && defined(__GNUC__)
#define USE_REG
#define DEF_FUNC
#include "reg_msg.h"
#endifvoid RegNetMsg() {mapNetMsg =new_swiss_map(sizeof(uint16_t), hashInt16, sizeof(fnCB), equal_int16);#if !defined(__clang__) && defined(__GNUC__)#undef DEF_FUNC#define REG_MSG
#endif
#define USE_REG
#include "reg_msg.h"
}

这样就可以非常方便地在netmsg.h中映射网络消息处理函数了:

DEFINE_HANDLER(ReqLogin, req_login);
DEFINE_HANDLER(Ping, ping_pong);

如果对你有帮助,欢迎点赞收藏!

http://www.dtcms.com/wzjs/383665.html

相关文章:

  • 网站搭建说明北大青鸟培训机构靠谱吗
  • 南通网站建设推广sem外包
  • 搜索引擎 wordpressseo优化啥意思
  • 90设计网站怎么样广告公司取名字参考大全
  • sem和网站建设的关系三门峡网站seo
  • 网站建设要花钱吗重庆电子商务seo
  • 做网站怎样安全采集会计培训班推荐
  • 做网站好还是阿里巴巴好搜索引擎优化seo多少钱
  • 知名网站建设哪家好专业网络推广机构
  • 网站建设公司武汉个人免费网上注册公司
  • 解析域名后怎么弄网站最新疫情最新情况
  • asp.net 网站计数器香港疫情最新消息
  • 免费上外国网站的浏览器一个完整的营销策划方案范文
  • 深圳中小型网站建设公司seo社区
  • 网站开发的测试内容郑州网站建设七彩科技
  • 写出电子商务网站的建设流程百度云怎么找资源
  • 大学生做偷拍视频网站扬州网站推广公司
  • 没有备案的网站百度能收录短视频推广引流
  • 邢台专业网站建设公司推荐百度指数指的是什么
  • 顺义区建设委员会网站长春网站开发
  • 郑州汽车网站建设哪家好sem与seo的区别
  • 基于b2c网站建设网站seo教材
  • 廉江网站开发公司苏州seo免费咨询
  • 建设个网站需要什么竞价外包运营
  • 用php做网站要用构架吗电脑培训班附近有吗
  • 网站建设报价百度电商广告代运营
  • 北京游戏网站建设淄博百度推广
  • 中国商标注册查询官网企业seo排名费用报价
  • 四川遂宁做网站的公司口碑营销的优缺点
  • 武汉网站制作报价德州网站建设优化