动手实现一个简单的 rpc 框架到入门 grpc (下)
之前手动实现了一次简陋的 rpc 调用,为了简单使用了 json 编码信息,其实这是非常不可靠的,go 中 json 解析会有一些问题,比如整数会变成浮点数,而且 json 字符串比较占空间。
gRPC 由 google 开发,是一款语言中立、平台中立、开源的 RPC 框架,默认使用 protocol buffers 来序列化和传输消息,基于 http2。
protobuf
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
先编写 proto 文件,再编译成 go 文件,新建 proto/hello.proto 文件
// proto/hello.proto
syntax = "proto3";
package proto;
message String {
string value = 1; // 类型 字段 字段标识符
}
// 定义服务
service HelloService {
rpc Hello (String) returns (String);
}
安装 protobuf 编译器用于编译 proto 文件,比如使用 scoop 安装 scoop install protobuf,或者手动下载安装
protobuf 编译工具可以把 proto 模板编译成多种语言,默认不支持 go,安装一下 go 插件
$ go get -u github.com/golang/protobuf/proto
$ go get -u github.com/golang/protobuf/protoc-gen-go
进入 hello.proto 文件目录,编译生成 hello.pb.go,后续为了方便可以把编译指令写成 shell 脚本
$ protoc -I . --go_out=plugins=grpc:. ./hello.proto
生成的 hello.pb.go 有一些接口和方法(省略了其他的),使用时候只需要实现接口调用对应方法
type HelloServiceServer interface {
Hello(context.Context, *String) (*String, error)
}
func RegisterHelloServiceServer(s *grpc.Server, srv HelloServiceServer) {
s.RegisterService(&_HelloService_serviceDesc, srv)
}
type helloServiceClient struct {
cc grpc.ClientConnInterface
}
func NewHelloServiceClient(cc grpc.ClientConnInterface) HelloServiceClient {
return &helloServiceClient{cc}
}
func (c *helloServiceClient) Hello(ctx context.Context, in *String, opts ...grpc.CallOption) (*String, error) {
out := new(String)
err := c.cc.Invoke(ctx, "/proto.HelloService/Hello", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
grpc
安装 grpc
$ go get -u google.golang.org/grpc
服务端
在 proto 文件夹同级新建 sever/server.go 文件,实现 server 接口,注册服务
type HelloServiceImpl struct{}
func (p *HelloServiceImpl) Hello(ctx context.Context, args *proto.String) (*proto.String, error) {
reply := &proto.String{Value: "hello " + args.GetValue()}
return reply, nil
}
func main() {
grpcServer := grpc.NewServer()
proto.RegisterHelloServiceServer(grpcServer, new(HelloServiceImpl))
lis, err := net.Listen("tcp", ":1234")
if err != nil {
log.Fatal(err)
}
grpcServer.Serve(lis)
}
客户端
在 proto 文件夹同级新建 sever/server.go 文件,调用服务
func main() {
conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure())
if err != nil {
log.Fatal(err)
}
defer conn.Close()
client := proto.NewHelloServiceClient(conn)
reply, err := client.Hello(context.Background(), &proto.String{Value: "world"})
if err != nil {
log.Fatal(err)
}
fmt.Println(reply.GetValue())
}
验证
首先运行服务端 go run server/server.go,再运行客户端
$ go run client/client.go
hello world
这里只简单介绍了用法,关于 protobuf 的更多用法可以参考 https://developers.google.com/protocol-buffers/,关于 protobuf 的原理可以参考 https://blog.csdn.net/carson_ho/article/details/70568606,另外 grpc 还支持流式调用。
流式调用
数据传输是流式的,服务端和服务端不用输完全部数据后才响应,流式传输可以是客户端流式、或服务端流式,也可以同时流式传输,只需要一个 stream 标识
service HelloService {
rpc Hello (String) returns (String);
rpc HelloStream (String) returns (stream String); //服务端流式响应
//rpc HelloStream (stream String) returns (String); //客户端端流式发送
//rpc HelloStream (stream String) returns (stream String); //双向流
}
重新编译,然后在 server/server.go 新增方法
func (HelloServiceImpl) HelloStream(args *proto.String, stream proto.HelloService_HelloStreamServer) error {
for i := 0; i < 10; i++ {
_ = stream.Send(&proto.String{Value: "hello " + args.GetValue() + strconv.Itoa(i)})
}
return nil
}
在 client/client.go 中调用 HelloStream 方法
stream, _ := client.HelloStream(context.Background(), &proto.String{Value: "World"})
for {
res, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Printf("stream.Recv: %v", err)
}
log.Printf("%s", res.String())
}
验证,首先运行 server,然后运行 client
$ go run server/server.go
$ go run client/client.go
2020/07/21 07:41:10 value:"hello World0"
2020/07/21 07:41:10 value:"hello World1"
2020/07/21 07:41:10 value:"hello World2"
2020/07/21 07:41:10 value:"hello World3"
2020/07/21 07:41:10 value:"hello World4"
2020/07/21 07:41:10 value:"hello World5"
2020/07/21 07:41:10 value:"hello World6"
2020/07/21 07:41:10 value:"hello World7"
2020/07/21 07:41:10 value:"hello World8"
2020/07/21 07:41:10 value:"hello World9"
动手实现一个简单的 rpc 框架到入门 grpc (下)的更多相关文章
- 动手实现一个简单的 rpc 框架到入门 grpc (上)
rpc 全称 Remote Procedure Call 远程过程调用,即调用远程方法.我们调用当前进程中的方法时很简单,但是想要调用不同进程,甚至不同主机.不同语言中的方法时就需要借助 rpc 来实 ...
- 徒手撸一个简单的RPC框架
来源:https://juejin.im/post/5c4481a4f265da613438aec3 之前在牛逼哄哄的 RPC 框架,底层到底什么原理得知了RPC(远程过程调用)简单来说就是调用远程的 ...
- 动手写一个简单的Web框架(模板渲染)
动手写一个简单的Web框架(模板渲染) 在百度上搜索jinja2,显示的大部分内容都是jinja2的渲染语法,这个不是Web框架需要做的事,最终,居然在Werkzeug的官方文档里找到模板渲染的代码. ...
- 动手写一个简单的Web框架(Werkzeug路由问题)
动手写一个简单的Web框架(Werkzeug路由问题) 继承上一篇博客,实现了HelloWorld,但是这并不是一个Web框架,只是自己手写的一个程序,别人是无法通过自己定义路由和返回文本,来使用的, ...
- 动手写一个简单的Web框架(HelloWorld的实现)
动手写一个简单的Web框架(HelloWorld的实现) 关于python的wsgi问题可以看这篇博客 我就不具体阐述了,简单来说,wsgi标准需要我们提供一个可以被调用的python程序,可以实函数 ...
- 自己动手写一个简单的MVC框架(第一版)
一.MVC概念回顾 路由(Route).控制器(Controller).行为(Action).模型(Model).视图(View) 用一句简单地话来描述以上关键点: 路由(Route)就相当于一个公司 ...
- 一个简单的"RPC框架"代码分析
0,服务接口定义---Echo.java /* * 定义了服务器提供的服务类型 */ public interface Echo { public String echo(String string) ...
- 自己动手写一个简单的MVC框架(第二版)
一.ASP.NET MVC核心机制回顾 在ASP.NET MVC中,最核心的当属“路由系统”,而路由系统的核心则源于一个强大的System.Web.Routing.dll组件. 在这个System.W ...
- 一个简单的RPC框架
一个 系统模型 二.数据库代码实现 1. mkdir database cd database vim dbInit.c /* * * Database Init tool * */ #include ...
随机推荐
- jquery-form详解
jQuery-Form 概观 jQuery表单插件允许您轻松而不显眼地升级HTML表单以使用AJAX.主要方法ajaxForm和ajaxSubmit从表单元素收集信息以确定如何管理提交过程.这两种方法 ...
- junit基本介绍视频笔记1
程序员每天工作的基本流程: 1.从svn检出代码: 2.运行单元测试,测试无误,进入下一步: 3.开始一天的代码编写工作: 4.代码提交到服务器之前进行单元测试: 5.单元测试通过提交到svn服务器. ...
- JavaScript基础有关构造函数、new关键字和this关键字(009)
1. 总是记得用new关键字来执行构造函数.前面提到,可以用构造函数创建JavaScript的对象,这个构造函数在使用的时候需要使用new关键字,但如果忘记写入new关键字,会怎么样?事实上这个函数还 ...
- 《UNIX环境高级编程》(APUE) 笔记系列
本系列笔记主要是对于 <UNIX环境高级编程>(APUE) 各章节内容 概念性的总结 ,不涉及代码解读 . 目录 : 第一章 UNIX基础知识 第二章 UNIX标准及实现 第三章 文件I/ ...
- 断路器Hystrix(Ribbon)
微服务架构中,根据业务划分成若干个服务,各单元应用间通过服务注册与订阅的方式互相依赖,依赖通过远程调用的方式执行,该方式难以避免因网络或自身原因而出现故障或者延迟,从而并不能保证服务的100%可用,此 ...
- Flutter vs React Native vs Native:深度性能比较
老孟导读:这是老孟翻译的付费文章,文章所有权归原作者所有. 欢迎加入老孟Flutter交流群,每周翻译2-3篇付费文章,精彩不容错过. 原文地址:https://medium.com/swlh/flu ...
- openstack cinder-backup流程与源码分析
在现在的云计算大数据环境下,备份容灾已经变成了一个炙手可热的话题,今天,和大家一起分享一下openstack是怎么做灾备的. [首先介绍快照] snapshot可以为volume创建快照,快照中保存了 ...
- 2.在linux安装ssh_免密连接
Linux开启ssh服务 首先更新源 sudo apt-get update 安装ssh服务 sudo apt-get install openssh-server 检测是否已启动 ps -e | g ...
- 《MapReduce: Simplified Data Processing on Large Clusters》论文研读
MapReduce 论文研读 说明:本文为论文 <MapReduce: Simplified Data Processing on Large Clusters> 的个人理解,难免有理解不 ...
- 我的第一个Maven工程
橘子松今天学了下maven 跑了个demo 其中也发现一些问题 并解决了 环境搭建 开始新建会有红叉. 在pom.xml里加入从你的本地仓库加入servlet-api.jar 如果没有 http:// ...