Thrift 的C与golang语言实现以及相互调用方式
来源:互联网 发布:unity3d 麻将 编辑:程序博客网 时间:2024/06/05 02:22
- Thrift 的Go与C语言实现
- thrift 文件编写
- Go与C的thrift代码
- Go的server端实现
- Go的客户端实现
- C的客户端实现
- C代码中调用Go的客户端
Thrift 的Go与C语言实现
Thrift 是Facebook为了解决各系统间大数据量的传输通信以及系统之间语言环境不同而设计的一种传输框架。目前来看常用的主流语言Thrift都已经很好地支持,并且github上已经有很多实现,除了C语言之外。Thrift传输的程序的静态数据,即数据的数据结构必须事前固定。Thrift原理就不介绍了,理论性东西网上很多,并且都是雷同的。下面通过实例介绍Thrift 接口在Go与C语言下的实现,以及如何在C语言中调用Go所编写的Thrift客户端。
1. thrift 文件编写
#example.thrift namespace go thrift.rpc struct Response { 1: required string data; }service RpcService { Response Test(1:string input)}
2. Go与C的thrift代码
thrift -r --gen go example.thriftthrift -r --gen c_glib example.thrift
此时在目录下会出现gen-go与gen-c_gib两个文件夹,里边存放着Thrift自动生成的数据结构体以及函数的声明。
3. Go的server端实现
/* server.go */package mainimport ( "./gen-go/thrift/rpc" "git.apache.org/thrift.git/lib/go/thrift" "log" "os")const ( NetworkAddr = "localhost:9090")type RpcServiceImpl struct {}func (this *RpcServiceImpl) Test(input string) (r *rpc.Response, err error) { //函数具体实现 return}func main() { transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory()) protocolFactory := thrift.NewTBinaryProtocolFactoryDefault() serverTransport, err := thrift.NewTServerSocket(NetworkAddr) if err != nil { log.Println("Error!", err) os.Exit(1) } handler := &RpcServiceImpl{} processor := rpc.NewRpcServiceProcessor(handler) log.Println("thrift server in", NetworkAddr) server.Serve()}
4. Go的客户端实现
/* client.go */import ( "./gen-go/thrift/rpc" "fmt" "git.apache.org/thrift.git/lib/go/thrift" "net" "os")func main(){ip := "127.0.0.1"port := "9090"input :="" transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory()) protocolFactory := thrift.NewTBinaryProtocolFactoryDefault() tSocket, err := thrift.NewTSocket(net.JoinHostPort(ip, port)) if err != nil { fmt.Fprintln(os.Stderr, "Error resolving address, ", err) os.Exit(1) } tTransport, _ := transportFactory.GetTransport(tSocket) client := rpc.NewRpcServiceClientFactory(tTransport, protocolFactory) if err := tTransport.Open(); err != nil { fmt.Fprintln(os.Stderr, (fmt.Errorf("Error opening socket to %s:%s : %v", ip, port, err))) os.Exit(1) } defer tTransport.Close() resp, _ := client.Test(input)}
C的客户端实现
C 的客户端实现目前在github一个都没有,Thrift好像也是最近才支持的。thrift是一种面向对象的框架,C语言面向对象的实现必须依赖于gobject库,所以这里边在实现的过程中需要注意一点,对thrift文件中定义的struct,其他可以直接实例化为对象,在C中必须使用g_object_new函数进行初始化,要不然改strcut 将无法实现。在会一直出现无法找到对应结构接收server端传来的参数。
/* client.c */#include <stdio.h>#include <glib-object.h>#include <string.h>#include <thrift/c_glib/protocol/thrift_binary_protocol.h>#include <thrift/c_glib/transport/thrift_framed_transport.h>#include <thrift/c_glib/transport/thrift_socket.h>#include "gen-c_glib/rpc_service.h"struct thrift_if{ ThriftSocket *socket; ThriftTransport *transport; ThriftProtocol *protocol; RpcServiceIf *client;};void if_open (struct thrift_if* if_instance, gchar *hostname, gint32 port, GError **error){#if (!GLIB_CHECK_VERSION (2, 36, 0)) g_type_init ();#endif if_instance->socket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", hostname, "port", port, NULL); if_instance->transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, "transport", if_instance->socket, NULL); if_instance->protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport", if_instance->transport, NULL); thrift_transport_open (if_instance->transport, error); if(!error){ return; } if_instance->client = g_object_new (TYPE_RPC_SERVICE_CLIENT, "input_protocol", if_instance->protocol, "output_protocol", if_instance->protocol, NULL);}void if_close (struct thrift_if *if_instance, GError **error){ g_clear_error (error); thrift_transport_close (if_instance->transport, NULL); g_object_unref (if_instance->client); g_object_unref (if_instance->protocol); g_object_unref (if_instance->transport); g_object_unref (if_instance->socket);}int main(){ gchar *hostname = "127.0.0.1"; gint32 port = 9090; gchar *input = "" struct thrift_if if_instance; GError *error = NULL; if_open(&if_instance, hostname, port, &error); gchar *data; Response *Res; Res = g_object_new(TYPE_RESPONSE,NULL); if (!error && rpc_service_if_test(if_instance.client,&Res,input,&error)){ g_object_get (Res, "data", &data, NULL); } if_close(&if_instance, &error);return 0;}
编译:gcc client.c gen-c_glib/rpc_service.c gen-c_glib/sven_types.c -o client -lthrift_c_glib -lgobject-2.0
5. C代码中调用Go的客户端
由于C的客户端编译依赖于thrift_c_glib与 gobject 动态库,并且thrift_c_glib动态库中对linux的一些系统库又进行了引用,所以动态库的依赖关系复杂,不利于在客户端稳定、无依赖的部署。
可以采用使用Go编写客户端,然后编译为.so文件,供C程序调用。因为Go采用静态源码编译方式,可以无依赖的移植到各个服务器中,在过程中需要注意C与Go基本数据结构之间的转化。代码与go client的实现基本相同,只是go 与 C直接不允许 struct的传递,所以只能传递基本数据类型
/*client.go */ package mainimport ( "./gen-go/thrift/rpc" "C" "fmt" "git.apache.org/thrift.git/lib/go/thrift" "net" "os")/* !!!务必写上"//export Test", 这不是注释 !!!*///export Testfunc Test (input string, ip string, port string) *C.char { transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory()) protocolFactory := thrift.NewTBinaryProtocolFactoryDefault() tSocket, err := thrift.NewTSocket(net.JoinHostPort(ip, port)) if err != nil { fmt.Fprintln(os.Stderr, "Error resolving address, ", err) os.Exit(1) } tTransport, _ := transportFactory.GetTransport(tSocket) client := rpc.NewRpcServiceClientFactory(tTransport, protocolFactory) if err := tTransport.Open(); err != nil { fmt.Fprintln(os.Stderr, (fmt.Errorf("Error opening socket to %s:%s : %v", ip, port, err))) os.Exit(1) } defer tTransport.Close() resp, _ := client.Test(input) return C.CString(resp.Data)}
编译为动态库,执行下面命令会生成libclient.h 与 libclient.so两个文件。
go build -buildmode=c-shared -o libclient.so client.go
C 语言调用该 Go生成的动态库:
#include <stdio.h>#include "libclient.h"int main(){ GoString input = {(char*)"test", 4}; GoString ip = {(char*)"127.0.0.1", 9}; GoString port = {(char*)"9090", 4}; char *res = NULL; res = Test(input, ip, port); if (res != NULL) { printf("%s\n", res); } return 0;}
阅读全文
0 0
- Thrift 的C与golang语言实现以及相互调用方式
- 用thrift实现多语言相互调用
- Golang通过Thrift框架完美实现跨语言调用
- Golang通过Thrift框架完美实现跨语言调用
- Golang通过Thrift框架完美实现跨语言调用
- C语言与汇编语言的相互调用
- Go语言学习之cgo(golang与C语言相互调用)
- C语言与汇编语言相互调用原理以及实例
- C语言与汇编语言相互调用原理以及实例
- 使用thrift做c++,java和python的相互调用
- extern C实现C与C++函数的相互调用
- extern C(C++与C实现相互函数的调用)
- C语言与汇编语言相互调用
- c语言和c++的相互调用
- OC与Swift语言的相互调用
- C 与 Fortran 的相互调用
- C++与C的相互调用
- C与C++的相互调用问题
- LightOJ
- 1149: 组合三位数之二
- ROM 之 任意波形发生器
- Nginx负载均衡
- 在WIN8下进行LINUX虚拟机搭建
- Thrift 的C与golang语言实现以及相互调用方式
- hiho一下 第158周 非法二进制数
- python and 和 or的用法
- 日记二 断点续传
- UVa 11988 破损的键盘 链表 双向队列
- 伪类与伪元素
- 【组合数学】八(容斥原理)
- 如何安装mayavi(以python 3.5为例)
- 4G模块网络通信