go语言使用grpc和gateway教程

本文详述了如何在Go中使用gRPC和JSON-RPC,包括服务端和客户端的实现,以及使用protobuf编译为gRPC和gateway。文章探讨了gRPC的缺点,如代码量大,并提出使用protobuf改进。还介绍了protobuf语法和命令,以及gRPC的流式传输和HTTP/gRPC网关的实现。最后,展示了实战中生成和使用SSL证书的步骤。
摘要由CSDN通过智能技术生成

jsonrpc

把jsonrpc.ServeConn(conn)改为grpc.ServeConn(conn)就是grpc了

为什么用jsongrpc?

因为grpc使用的为go语言独有的数据序列化gob,导致其他语言无法解析;

使用jsonrpc的话数据序列化就使用json这样其他语言都可以解析使用

服务端

type user struct {
   
}

func (u user) Hello(name string, res *string) error {
   
   *res = name + "  over!"
   return nil
}
func main() {
   
   // 注册服务
   err := rpc.RegisterName("hello", new(user))
   if err != nil {
   
      fmt.Println("rpc.RegisterName err", err)
      return
   }
   // 启动监听
   listen, err := net.Listen("tcp", "localhost:8888")
   if err != nil {
   
      fmt.Println("net.Listen err", err)
      return
   }
   for true {
   
      // 建立连接
      conn, err := listen.Accept()
      if err != nil {
   
         fmt.Println("listen.Accept err", err)
         return
      }
      // 绑定服务
      go jsonrpc.ServeConn(conn)
   }
}

客户端

func main() {
   
   // 连接
   dial, err := jsonrpc.Dial("tcp", "localhost:8888")
   if err != nil {
   
      fmt.Println("jsonrpc.Dial", err)
      return
   }
   var str string
   // 调用
   err = dial.Call("hello.Hello", "zz", &str)
   if err != nil {
   
      fmt.Println("dial.Call err", err)
   }
   fmt.Println("aaaa:", str)
}

缺点

这样写代码的话会导致代码量太高,注册服务不好查看

改进

使用protobuf来编写服务

protobuf

谷歌出的一种数据序列化语言,和其他数据序列化语言比较,protobuf简单、数据之间传输更小、更快

语法

详细语法百度查看

// 声明版本
syntax = "proto3";

// 包
package pb;

//  生成go语言所在包
option go_package = "../pb";

// 相当于struct
message Tea {
  int32 age = 1;
  string name = 2;
}

//  服务
service HelloWorld {
  rpc Test1(Tea) returns (Tea);
}

命令

proto编译grpc

protoc --go_out=. --go_opt=paths=source_relative \
    --go-grpc_out=. --go-grpc_opt=paths=source_relative \
    ./*.proto

proto编译getaway

protoc \
  --go_out . --go_opt paths=source_relative \
  --go-grpc_out . --go-grpc_opt paths=source_relative \
  --grpc-gateway_out . --grpc-gateway_opt paths=source_relative \
  ./proto/rest.proto

protoGRPC

入门篇

.proto

使用命令编译为go文件。编译命令看上文

syntax = "proto3";

package pb;

option go_package = "../pb";

message Tea {
  int32 age = 1;
  string name = 2;
}

service HelloWorld {
  rpc Test1(Tea) returns (Tea);
}

server.go

type stu struct {
   
}

/* 实现pb下的服务端接口
type HelloWorldServer interface {
	Test1(context.Context, *Tea) (*Tea, error)
}
*/

func (s stu) Test1(ctx context.Context, tea *pb.Tea) (*pb.Tea, error) {
   
	tea.Name = "hello"
	tea.Age = 66
	return tea, nil
}

func main() {
   
  //	创建服务
	server := grpc.NewServer()
  //	注册服务
	pb.RegisterHelloWorldServer(server, new(stu))
  //	启动监听
	listen, err := net.Listen("tcp", "localhost:9999")
	if err != nil {
   
		fmt.Println(err)
	}
  //	启动服务
	server.Serve(listen)
}

client.go

客户端不需要实现接口

grpc.WithInsecure():后边会解决这个问题

func main() {
   
   //	连接
   dial, err := grpc.Dial("localhost:9999", grpc.WithInsecure())
   if err != nil {
   
      fmt.Println(err)
   }
   //	创建客户端
   client := pb.NewHelloWorldClient(dial)
   tea := new(pb.Tea)
   tea.Name = "abc"
   //	调用服务
   t, err := client.Test1(context.TODO(), tea)
   if err != nil {
   
      fmt.Println(err)
   }
   //	输出返回值
   fmt.Println(t.Name, "-->", t.Age)
}

进阶篇

.proto

流式传输,相当于一个不断开的连接可以一直传输数据

syntax = "proto3";

package pb;

option go_package = "./proto";

message Req {
  string message = 1;
}

message Res {
  string message = 1;
}

service HelloGRPC {
  rpc SayHi(Req) returns (Res);
  //	输入流
  rpc SayHiIn(stream Req) returns (Res);
  //	输出流
  rpc SayHiOut(Req) returns (stream Res);
  //	输入输出流
  rpc SayHiIO(stream Req) returns (stream Res);
}

server.go/client.go

服务端注册

func main() {
   
   listen, err := net.Listen("tcp", ":8888")
   if err != nil {
   
      fmt.Println("注册失败", err.Error())
      return
   }
   defer listen.Close()
   newServer := grpc.NewServer()
   pb.RegisterHelloGRPCServer(newServer, &server{
   })
   newServer.Serve(listen)
   reflection.Register(newServer)
}

客户端调用

func main() {
   
   conn, err := grpc.Dial(":8888", grpc.WithTransportCredentials(insecure.NewCredentials()))
   if err != nil {
   
      fmt.Println("连接失败", err.Error())
      return
   }
   defer conn.Close()
   client := pb.NewHelloGRPCClient(conn)
   //sayHi(client)
   //sayHiIn(client)
   //sayHiOut(client)
   sayHiIO(client)
}

服务端实现接口

/*
实现pb的服务端接口
type HelloGRPCServer interface {
	SayHi(context.Context, *Req) (*Res, error)
	SayHiIn(HelloGRPC_SayHiInServer) error
	SayHiOut(*Req, HelloGRPC_SayHiOutServer) error
	SayHiIO(HelloGRPC_SayHiIOServer) error
	mustEmbedUnimplementedHelloGRPCServer()
}
*/
type server struct {
   
   pb.UnimplementedHelloGRPCServer
}

客户端不需要实现

普通传输

服务端

func (s server) SayHi(ctx context.Context, req *pb.Req) (*pb.Res
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值