This is a creation in Article, where the information may have evolved or changed.
- Thrift's go and C language implementations
- Thrift File Preparation
- Thrift code for Go and C
- Server-side implementation of Go
- The client implementation of Go
- C's Client implementation
- Call the Go client in C code
Thrift's go and C language implementations
Thrift 是Facebook为了解决各系统间大数据量的传输通信以及系统之间语言环境不同而设计的一种传输框架。目前来看常用的主流语言Thrift都已经很好地支持,并且github上已经有很多实现,除了C语言之外。Thrift传输的程序的静态数据,即数据的数据结构必须事前固定。Thrift原理就不介绍了,理论性东西网上很多,并且都是雷同的。下面通过实例介绍Thrift 接口在Go与C语言下的实现,以及如何在C语言中调用Go所编写的Thrift客户端。
1. Thrift File Preparation
#example.thrift namespace go thrift.rpc struct Response { 1string data; }service RpcService { Response Test(1:string input)}
2. Thrift code for Go and C
thrift-r--gengoexample.thriftthrift-r--genc_glibexample.thrift
At this point in the directory will appear gen-go and Gen-c_gib two folders, which contains thrift automatically generated data structure body and function declaration.
3. Server-side implementation of Go
/ * Server.go * / PackageMainImport("./gen-go/thrift/rpc" "Git.apache.org/thrift.git/lib/go/thrift" "Log" "OS")Const(networkaddr ="localhost:9090")typeRpcserviceimplstruct{}func(This *rpcserviceimpl) Test (inputstring) (R *rpc. Response, err Error) {//function specific implementation return}funcMain () {transportfactory: = thrift. Newtframedtransportfactory (Thrift. Newttransportfactory ()) Protocolfactory: = Thrift. Newtbinaryprotocolfactorydefault () Servertransport, err: = Thrift. Newtserversocket (NETWORKADDR)ifErr! =Nil{log. Println ("error!", err) OS. Exit(1)} Handler: = &rpcserviceimpl{} Processor: = RPC. Newrpcserviceprocessor (handler) log. Println ("Thrift Server in", networkaddr) server. Serve ()}
4. The client implementation of 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's Client implementation
The client implementation of C is currently not available on GitHub, and thrift seems to be supporting it recently. Thrift is an object-oriented framework, C language object-oriented implementation must rely on the GObject library, so here side in the implementation of the process need to note that the thrift file defined in the struct, the other can be directly instantiated to the object, in C must use the G_object_ The new function is initialized, or strcut will not be implemented. There will always be a parameter that cannot be found on the receiving server side of the corresponding structure.
/* 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;}; voidif_open (struct Thrift_if*if_instance, Gchar *hostname, Gint32 port, Gerror **error) {#if (! Glib_check_version (2, 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);} voidif_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);} IntMain() {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.-o-lthrift_c_glib-lgobject-2.0
5. Call the Go client in C code
Because the client-side compilation of C relies on the thrift_c_glib and GObject dynamic libraries, and some of the Linux system libraries are referenced in the Thrift_c_glib dynamic library, the dependency of the dynamic library is complex, which is not conducive to the stable, non-dependent deployment of the client.
You can use go to write the client, and then compile the. So file for the C program to call. Because go uses static source code to compile the way, can migrate to each server without dependency, need to pay attention to the transformation between C and go basic data structure in the process. The code is basically the same as the go client implementation, except that go and C directly do not allow the transfer of structs, so only basic data types can be passed
/*client.go * *Package Mainimport ("./gen-go/thrift/rpc" "C" "FMT" "Git.apache.org/thrift.git/lib/go/thrift" "NET" "OS")/ *!! Be sure to write "//export Test", this is not a comment!!! */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)}
Compiled to a dynamic library, execute the following command to generate Libclient.h and libclient.so two files.
-buildmode=c-shared-o libclient.so client.go
The C language calls the go-generated dynamic library:
#include <stdio.h> #include" libclient.h " int Main () {gostring input = {( Span class= "Hljs-keyword" >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 ;}