美文网首页
五. Go(Go protobuf)

五. Go(Go protobuf)

作者: 冰菓_ | 来源:发表于2022-07-28 23:06 被阅读0次
gopath开发模式和go modules开发模式对比
goland创建项目时没用go mod模式选项的坑

在GoLand 2021.2 稳定版的更新文档里有一些对go modules的更新,欢迎界面的默认 Go 选项现在是 Go modules 项目的默认选项

解决warning: go env -w GOPROXY=... does not override conflicting OS environment variable问题
Go语言编码规范

Go语言编码规范 - Go语言中文网

什么是rpc?rpc开发的挑战是什么?
  1. Call ID映射:在本地调用中,函数体是直接通过函数指针来指定的,我们调用add,编译器就自动帮我们调用它相应的函数指针。但是在远程调用中,函数指针是不行的,因为两个进程的地址空间是完全不一样的。所以,在RPC中,所有的函数都必须有自己的一个ID。这个ID在所有进程中都是唯一确定的。客户端在做远程过程调用时,必须附上这个ID。
  2. 序列化和反序列化。客户端怎么把参数值传给远程的函数呢?在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。但是在远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。甚至有时候客户端和服务端使用的都不是同一种语言(比如服务端用C++,客户端用Java或者Python)。这时候就需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。
  3. 网络传输。远程调用往往用在网络上,客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把Call ID和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传回客户端。
通过http完成简单的服务端的功能
客户端
1. 建立tcp/http连接
2, 将对象序列化成json字符串 -- 序列化
3. 发送json -- 调用成功后实际上你接收的是一个二级制的数据
4. 等待服务器发送结果
5. 将服务器返回的数据解析成对象 -- 反序列化

服务端
1. 监听端口
2. 读取数据 -- 二级制的json数据
3. 对数据进行反系列化对象
4. 开始处理业务逻辑
5. 将处理后的结果序列化为json二级制数据 -- 序列化
6. 将数据返回

反序列化和序列化是可以选择的,不一定采用json,xml,protobuf,msgpack
func main() {
    //http://localhost:8000/add?a=1&b=2
    http.HandleFunc("/add", func(w http.ResponseWriter, r *http.Request) {
        //callID的问题,r.URL.PATH 数据传输协议 url的参数协议 网络传输协议http
        _ = r.ParseForm()
        fmt.Println("path: ", r.URL.Path)
        a, _ := strconv.Atoi(r.Form["a"][0])
        b, _ := strconv.Atoi(r.Form["b"][0])
        w.Header().Set("Content-Type", "application/json")
        data, _ := json.Marshal(map[string]int{
            "data": a + b,
        })
        _, _ = w.Write(data)

    })

    _ = http.ListenAndServe("127.0.0.1:8000", nil)
}
import (
    "encoding/json"
    "fmt"
    "github.com/kirinlabs/HttpRequest"
)

type ResponseDta struct {
    Data int `json:"Data"`
}

func add(a, b int) int {
    request := HttpRequest.NewRequest()
    response, _ := request.Get(fmt.Sprintf("http://127.0.0.1:8000/%s?a=%d&b=%d", "add", a, b))
    body, _ := response.Body()
    fmt.Println(string(body))
    responseDta := ResponseDta{}
    _ = json.Unmarshal(body, &responseDta)
    return responseDta.Data
}
func main() {
    add(2, 2)
}
go 内置rpc
type HelloService struct {
}

func (s *HelloService) Hello(request string, reply *string) error {
    *reply = "hell0 " + request
    return nil
}
func main() {
    // 1实例化一个server
    listen, err := net.Listen("tcp", "127.0.0.1:1234")
    // 2注册处理逻辑 handler
    err = rpc.RegisterName("HelloService", &HelloService{})
    // 3启动服务
    accept, _ := listen.Accept()
    rpc.ServeConn(accept)

}
func main() {
    client, _ := rpc.Dial("tcp", "127.0.0.1:1234")
    var reply string
    err := client.Call("HelloService.Hello", "bobby", &reply)
    if err != nil {
        panic("")
    }
    fmt.Println(reply)
}

....优化代码:封装和解耦:略

protoc-gen-go 安装踩坑记录

protoc-gen-go 安装踩坑记录

--go_out: protoc-gen-go: plugins are not supported问题处理

protoc-gen-go: plugins are not supported问题处理

protobuf和json的对比
syntax = "proto3";

option go_package = "." ;

message HelloRequest {
   string name = 1; // 1是编号
   int32 age = 2;
   repeated string course = 3;
}
 protoc -I . helloworld.proto  --go_out=plugins=grpc:. 
package main

import (
    "encoding/json"
    "fmt"
    "github.com/golang/protobuf/proto"
    "rpcProject/DAY3/proto"
)

type Hello struct {
    Name    string   `json:"name"`
    Age     string   `json:"age"`
    Courses []string `json:"courses"`
}

func main() {
    request := __.HelloRequest{
        Name:   "Bobby",
        Age:    18,
        Course: []string{"go", "java", "scala"},
    }
    hello := Hello{
        Name:    "bobby",
        Age:     "18",
        Courses: []string{"go", "java", "scala"},
    }
    protomarshal, _ := proto.Marshal(&request)
    jsonmarshal, _ := json.Marshal(hello)
    newrequest := __.HelloRequest{}
    fmt.Println(len(protomarshal), len(jsonmarshal))
    proto.Unmarshal(protomarshal, &newrequest)
    fmt.Println(newrequest.Name, newrequest.Age, newrequest.Course)
}
为什么需要安装protoc和protoc-gen-go
解决 "google.golang.org/grpc" 报红
gopath路径
grpc快速体验
syntax = "proto3";
option go_package = ".;proto";

service Greeter{
    rpc SayHello(HelloRequest) returns (HelloReply);
}

message HelloRequest {
    string name = 1;
}
message HelloReply {
   string message = 2;
}
type Server struct {
}

func (s *Server) SayHello(ctx context.Context, re *proto.HelloRequest) (*proto.HelloReply, error) {
    return &proto.HelloReply{
        Message: "hello" + re.Name,
    }, nil
}
func main() {
    server := grpc.NewServer()
    proto.RegisterGreeterServer(server, &Server{})
    listen, _ := net.Listen("tcp", "0.0.0.0:8081")
    _ = server.Serve(listen)

}
func main() {
    conn, _ := grpc.Dial("0.0.0.0:8081", grpc.WithInsecure())
    defer conn.Close()
    client := proto.NewGreeterClient(conn)
    reply, _ := client.SayHello(context.Background(), &proto.HelloRequest{
        Name: "bobby",
    })
    fmt.Println(reply.Message)
}
grpc的流模式

grpc的stream流模式

option go_package的作用

用于生成的.pb.go文件,在引用时和生成go包名时起作用,前一个参数用于指定生成文件的位置,后一个参数指定生成的 .go 文件的 package

option go_package = "{out_path};out_go_package";
proto文件中import另一个proto文件

protobuf 导入另一文件夹下的proto

疑问:这怎么解决
我这里可能没装插件,参考:protobuf中使用import需要注意的点
protobuf中的嵌套的message对象
protobuf中的enum枚举类型
protobuf中的map类型
protobuf内置的timestamp类型

Protobuf 教程

grpc的metadata机制
grpc的拦截器
通过拦截器和metadata实现grpc的auth认证
grpc的验证器
grpc的状态码
grpc中的错误处理
grpc的超时机制
protoc生成的go的源码里面有什么?

相关文章

网友评论

      本文标题:五. Go(Go protobuf)

      本文链接:https://www.haomeiwen.com/subject/iawfirtx.html