thrift c_glib 库序列化学习
最近在项目中需要在不同的语言(c, c++, java, python) 之间传递消息, 模式是 server(C++)需要向订阅者(observer) 发送更新.
大致的思路是server侦听某个端口, 然后observer 连接, 然后双方保持连接, 当有更新时, server 将消息下发给observer.
由于需要跨语言,所以我们需要一个序列化的库, 项目中之前引入的thrift 正好可以解决, 在需要支持的各种语言中, c语言由于本身没有面向对象, 所以特别单独学习了下thrift c_glib 的使用, 特此记录.
thrift c_glib
- thrift 是一个跨语言的RPC库, 自身带了很不错的网络框架,使用起来很简单, 基本上只需要很短的代码量就可以实现一个基于socket/HTTP的模式, 但是这个模式需要client端主动发起请求,然后server应答, 和我们的设计不太一致, 所以这里我只是把thrift 作为一个序列化的库来使用
- thrift 支持很多语言, 比如C++, Java, Python 等等, 但是它对C语言的支持需要glib 库, 并不是原生支持, 所以需要熟悉下glib库的用法
thrift c_glib 序列化例子
在安装好thrift 后, 我们需要编写消息体, 保存为 test.thrift
-
struct test { 1:boolean b1, 2:i32 i2, 3:string s3 }
可以注意到这里的格式,非常类似c, 然后执行命令
thrift -r --gen c_glib test.thrift
就会在gen-c_glib文件夹中生成对应的代码文件test_types.h, test_types.c
test_types.h 中定义了一些我们会用到的宏, 以及两个主要的结构体
-
struct _test { ThriftStruct parent; /* public */ gint32 i1; gboolean __isset_i1; gchar * s2; gboolean __isset_s2; }; typedef struct _test test; struct _testClass { ThriftStructClass parent; }; typedef struct _testClass testClass; GType test_get_type (void); #define TYPE_TEST (test_get_type()) #define TEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TEST, test)) #define TEST_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), _TYPE_TEST, testClass)) #define IS_TEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_TEST)) #define IS_TEST_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), TYPE_TEST)) #define TEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_TEST, testClass))
编写序列化过程
-
#include <string.h> #include <stdio.h> #include <glib-object.h> #include <thrift/c_glib/protocol/thrift_binary_protocol.h> #include <thrift/c_glib/transport/thrift_memory_buffer.h> #include "gen-c_glib/test_types.h" test* createTest(int num, const char* mesg) { test* t = g_object_new(TYPE_TEST, NULL); t->i1 = num; t->s2 = strdup(mesg); return t; } guchar* test2String(test* t, int* size) { ThriftTransport * transport = THRIFT_TRANSPORT(g_object_new(THRIFT_TYPE_MEMORY_BUFFER, "buf_size", 1024, NULL)); ThriftProtocol * protocol = THRIFT_PROTOCOL(g_object_new(THRIFT_TYPE_BINARY_PROTOCOL, "transport", transport, NULL)); thrift_struct_write(THRIFT_STRUCT(t), protocol, NULL); guchar* buf = (guchar*) g_malloc0(1024); *size = thrift_memory_buffer_read(THRIFT_TRANSPORT(transport), buf, 1024, NULL); g_object_unref(transport); g_object_unref(protocol); return buf; } test* string2Test(const guchar* buf, int size) { ThriftTransport * transport = THRIFT_TRANSPORT(g_object_new(THRIFT_TYPE_MEMORY_BUFFER, "buf_size", size, NULL)); ThriftProtocol * protocol = THRIFT_PROTOCOL(g_object_new(THRIFT_TYPE_BINARY_PROTOCOL, "transport", transport, NULL)); thrift_memory_buffer_write(transport, (gpointer)buf, size, NULL); test* t = g_object_new(TYPE_TEST, NULL); thrift_struct_read(THRIFT_STRUCT(t), protocol, NULL); g_object_unref(transport); g_object_unref(protocol); return t; } int main() { test * t = createTest(1024, "hello"); int size; guchar* buf = test2String(t, &size); g_object_unref(t); test * nt = string2Test(buf, size); g_free(buf); printf("%d %s\n", nt->i1, nt->s2); g_object_unref(nt); return 0; }
通过这样, 剩下的就只是server通过socket将转换成guchar的字符串 发送给客户端, 客户端在进行反序列化就可以得到信息了
时间: 2024-12-04 17:44:58