C/C++与Go之间的RPC

您所在的位置:网站首页 Go语言与C/C++进行交互 C/C++与Go之间的RPC

C/C++与Go之间的RPC

2024-07-17 10:50| 来源: 网络整理| 查看: 265

目前, rpc框架主要沿着两条路线发展,一个是目标为了跨语言,服务端可以用不同的语言实现,客户端也可以用不同的语言实现,不同的语言实现的客户端和服务器端可以互相调用。很显然,要支持不同的语言,需要基于那种语言实现相同协议的框架,并且协议设计应该也是跨语言的,其中比较典型的是 grpc,基于同一个IDL,可以生成不同语言的代码,并且语言的支持也非常的多。另一个rpc框架发展的目标是支持服务治理,主要的精力放在服务发现、路由、容错处理等方面,主要围绕一个语言开发,可能也有一些第三方曲折的实现服务的调用和服务的实现,这其中的代表,也是比较早的开源的框架就是阿里巴巴的dubbo。下文主要讲解前者。

搜索C/C++与Go之间的RPC,大多数都是利用thrift框架,但是很少有不用这些框架通信的,所以写下这篇blog。

首先,我们都是知道Go语言之间的RPC,也知道Go语言RPC有三种方式:

标准的RPC,基于http协议,采用gob编码,只能在Go语言进行RPC,不能跨语言(当然这不是绝对的,你可以使用C++在模拟gob编码来封装,同样也可以跨语言RPC)。基于JSON的RPC,大家都知道JSON是跨语言通用的协议,等会C/C++与Go之间的RPC也是采用这种协议实现。基于Protobuf的RPC。

 

介绍完一些基础概念,下面我们开始C/C++与Go之间的RPC:

上面也说了,主要采用JSON协议进行跨语言RPC,直接上代码,C/C++作为客户端,Go作为服务器

#include #include #include #include #include #include #include #define DEST_PORT 8096 #define DEST_IP "127.0.0.1" #define MAX_DATA 1024 int main() { int sockfd; struct sockaddr_in dest_addr; sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==-1){ printf("socket failed:%d",errno); } dest_addr.sin_family=AF_INET; dest_addr.sin_port=htons(DEST_PORT); dest_addr.sin_addr.s_addr=inet_addr(DEST_IP); bzero(&(dest_addr.sin_zero),8); if(connect(sockfd,(struct sockaddr*)&dest_addr,sizeof(struct sockaddr))==-1){ printf("connect failed:%d",errno); } else{ char data[] = "{\"id\":1000,\"method\":\"Arith.Divide\",\"params\":[{\"A\":9,\"B\":2}]}"; send(sockfd,data,strlen(data),0); printf("send success\n"); char buf[MAX_DATA] = {0}; while(1) { recv(sockfd,buf,MAX_DATA,0); if(strlen(buf) > 0){ printf("%s\n",buf); break; } } } close(sockfd); return 0; }

 其实主要就是31行,封装的JSON协议:

id:调用标识符。可以为字符串,不推荐包含小数(不能准确二进制化),或为null(可能引起混乱)。

method:调用的方法名。

params:方法传入的参数,若无参数则为null。

package main import ( "errors" "fmt" "log" "net" "net/rpc" "net/rpc/jsonrpc" "os" ) // 算数运算结构体 type Arith struct { } // 算数运算请求结构体 type ArithRequest struct { A int B int } // 算数运算响应结构体 type ArithResponse struct { Pro int // 乘积 Quo int // 商 Rem int // 余数 } // 乘法运算方法 func (this *Arith) Multiply(req ArithRequest, res *ArithResponse) error { res.Pro = req.A * req.B return nil } // 除法运算方法 func (this *Arith) Divide(req ArithRequest, res *ArithResponse) error { if req.B == 0 { return errors.New("divide by zero") } res.Quo = req.A / req.B res.Rem = req.A % req.B return nil } func main() { rpc.Register(new(Arith)) // 注册rpc服务 lis, err := net.Listen("tcp4", "127.0.0.1:8096") if err != nil { log.Fatalln("fatal error: ", err) } fmt.Fprintf(os.Stdout, "%s\n", "start connection") for { conn, err := lis.Accept() // 接收客户端连接请求 if err != nil { continue } go func(conn net.Conn) { // 并发处理客户端请求 fmt.Fprintf(os.Stdout, "%s,my add:%v peer add %v\n", "new client in coming",conn.LocalAddr(),conn.RemoteAddr()) jsonrpc.ServeConn(conn) }(conn) } }

运行:

先运行服务器再 运行客户端

id: 调用标识符,与调用方传入的标识一致,当请求中的id检查发生错误时(转换错误/无效请求),则必须返回null。

result:方法返回值,调用成功时,不能为null,调用错误时,必须为null。(对应的服务器注册函数的response指针参数)

error:调用时错误,无错误返回null,有错误时则返回一个错误对象。 (对应的服务器注册函数的返回值)

参考原文:

https://github.com/Unknwon/gcblog/blob/master/content/09-protorpc.md



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3