grpc 在 golang 使用

文章目录 (?) [+]

    Protocol Buffers

    1.安装编译器

    https://github.com/protocolbuffers/protobuf/releases 

    或者

    sudo apt -y install protobuf-compiler

    2.安装 go 插件

    go get -u github.com/golang/protobuf/protoc-gen-go

    3.编写 proto

    https://developers.google.com/protocol-buffers/docs/proto3

    https://developers.google.com/protocol-buffers/docs/gotutorial

    字段标号:1~299-1 (536, 870, 911),其中 19000 ~ 19999 为保留的字段标号。

    // 指定编译器版本,默认为 proto2
    syntax = "proto3";
    
    //package member;
    
    // 生成的 go 包名
    option go_package = "./member";
    
    message Member {
        // 字段类型 字段名 字段编号
        string name = 1;
        uint32 age = 2;
        // 可重复字段,go 中为切片
        repeated string emails = 3;
    }
    
    message Request {
        string msg = 1;
    }
    
    message Response{
        uint32 code = 1;
        string msg = 2;
        repeated bytes data = 3;
    }
    
    service ProfileService {
        rpc CreateMember (stream Member) returns (Response) {}
        rpc GetMember (Request) returns (stream Member) {}
    }

    应用

    在 rpc 中的使用

    代码生成

    protoc ./member.proto --go_out=.

    server.go

    package main
    
    import (
        "log"
        "net"
        "net/rpc"
        "member"
    )
    
    type Profile struct{}
    
    func (pro *Profile) GetName(m *member.Member, resp *member.Response) error {
        resp.Msg = m.GetName()
    
        return nil
    }
    
    func main() {
        err := rpc.Register(&Profile{})
        if err != nil {
            log.Fatalln(err)
        }
    
        ln, err := net.Listen("tcp", ":9008")
        if err != nil {
            log.Fatalln(err)
        }
    
        for {
            conn, err := ln.Accept()
            if err != nil {
                log.Println(err)
    
                continue
            }
    
            go rpc.ServeConn(conn)
        }
    }


    client.go

    package main
    
    import (
        "log"
        "net/rpc"
        "member"
    )
    
    func main() {
        m := &member.Member{
            Name:   "jack",
            Age:    27,
            Emails: []string{"jack@demo.com"},
        }
        client, err := rpc.Dial("tcp", "127.0.0.1:9008")
        if err != nil {
            log.Fatalln(err)
        }
        defer client.Close()
    
        resp := &member.Response{}
        err = client.Call("Profile.GetName", m, resp)
        if err != nil {
            log.Fatalln(err)
        }
    
        log.Fatalln(resp.GetMsg())
    }


    在 grpc 中的使用

    代码生成

    protoc ./member.proto --go_out=plugins=grpc:.

    证书生成

    # Country Name (2 letter code) [AU]:CN
    # State or Province Name (full name) [Some-State]:SD
    # Locality Name (eg, city) []:QD
    # Organization Name (eg, company) [Internet Widgits Pty Ltd]:LANSEYUJIE
    # Organizational Unit Name (eg, section) []:DevOps
    # Common Name (e.g. server FQDN or YOUR name) []:grpc-demo
    # Email Address []:test@lanseyujie.com
    openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.cer -subj "/C=CN/ST=SD/L=QD/O=LANSEYUJIE/OU=DevOps/CN=grpc-demo/emailAddress=test@lanseyujie.com"


    server.go

    package main
    
    import (
        "context"
        "google.golang.org/grpc"
        "google.golang.org/grpc/codes"
        "google.golang.org/grpc/credentials"
        "google.golang.org/grpc/metadata"
        "google.golang.org/grpc/status"
        "io"
        "log"
        "net"
        "member"
    )
    
    var memberList []*member.Member
    
    type Profile struct{}
    
    // Client Stream
    func (pro *Profile) CreateMember(stream member.ProfileService_CreateMemberServer) error {
        for {
            m, err := stream.Recv()
            if err != nil {
                if err == io.EOF {
                    log.Println("EOF")
                    resp := &member.Response{Code: 200, Msg: "all data recv"}
    
                    return stream.SendAndClose(resp)
                } else {
                    log.Println(err)
    
                    return err
                }
            }
    
            memberList = append(memberList, m)
            // 输出接收到的数据
            log.Println(m)
        }
    }
    
    // Server Stream
    func (pro *Profile) GetMember(req *member.Request, stream member.ProfileService_GetMemberServer) error {
        log.Println(req.GetMsg())
        for _, m := range memberList {
            err := stream.Send(m)
            if err != nil {
                log.Println(err)
    
                return err
            }
        }
    
        return nil
    }
    
    // 拦截器
    func TokenInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
        md, exist := metadata.FromIncomingContext(ctx)
        if !exist {
            return nil, status.Errorf(codes.Unauthenticated, "Unauthenticated")
        }
    
        var key, secret string
    
        if appKey, exist := md["appkey"]; exist {
            key = appKey[0]
        }
    
        if appSecret, exist := md["appsecret"]; exist {
            secret = appSecret[0]
        }
    
        if key != "abcd" || secret != "1234" {
            return nil, status.Errorf(codes.Unauthenticated, "Unauthenticated")
        }
    
        // 继续下一步
        return handler(ctx, req)
    }
    
    func main() {
        // TLS Server
        crd, err := credentials.NewServerTLSFromFile("./server.cer", "./server.key")
        if err != nil {
            log.Fatalln(err)
        }
        srv := grpc.NewServer(grpc.Creds(crd), grpc.UnaryInterceptor(TokenInterceptor))
    
        // Pure Server
        // srv := grpc.NewServer()
    
        // 注册服务
        member.RegisterProfileServiceServer(srv, &Profile{})
    
        // 监听 tcp 端口
        ln, err := net.Listen("tcp", ":9008")
        if err != nil {
            log.Fatalln(err)
    
            return
        }
    
        log.Fatalln(srv.Serve(ln))
    }


    client.go

    package main
    
    import (
        "context"
        "google.golang.org/grpc"
        "google.golang.org/grpc/credentials"
        "io"
        "log"
        "member"
    )
    
    type Token struct {
        AppKey    string
        AppSecret string
    }
    
    // metadata
    func (t *Token) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
        return map[string]string{
            "appkey":    t.AppKey,
            "appsecret": t.AppSecret,
        }, nil
    }
    
    // 是否使用 TLS 传输
    func (t *Token) RequireTransportSecurity() bool {
        return true
    }
    
    // 调用 CreateMember 方法
    func CreateMember(client member.ProfileServiceClient) {
        psc, err := client.CreateMember(context.Background())
        if err != nil {
            log.Println(err)
    
            return
        }
    
        memberList := []*member.Member{
            {Name: "jack", Age: 27, Emails: []string{"jack@demo.com"}},
            {Name: "linda", Age: 33, Emails: []string{"linda@demo.com"}},
            {Name: "tim", Age: 22, Emails: []string{"tim@demo.com"}},
        }
    
        for _, m := range memberList {
            err = psc.Send(m)
            if err != nil {
                panic(err)
            }
        }
    
        for {
            resp, err := psc.CloseAndRecv()
            if err != nil {
                if err == io.EOF {
                    log.Println("EOF")
                } else {
                    log.Println(err)
                }
    
                break
            }
            log.Println(resp.GetMsg())
        }
    }
    
    // 调用 GetMember 方法
    func GetMember(client member.ProfileServiceClient) {
        req := &member.Request{Msg: "hello"}
        psc, err := client.GetMember(context.Background(), req)
        if err != nil {
            log.Println(err)
    
            return
        }
    
        for {
            m, err := psc.Recv()
            if err != nil {
                if err == io.EOF {
                    log.Println("EOF")
                } else {
                    log.Println(err)
                }
    
                break
            }
    
            log.Println(m)
        }
    }
    
    func main() {
        crd, err := credentials.NewClientTLSFromFile("./server.cer", "grpc-demo")
        if err != nil {
            log.Fatalln(err)
        }
        token := &Token{
            AppKey:    "abc",
            AppSecret: "1234",
        }
    
        // TLS
        conn, err := grpc.Dial("127.0.0.1:9008", grpc.WithTransportCredentials(crd), grpc.WithPerRPCCredentials(token))
    
        // Pure
        // conn, err := grpc.Dial("127.0.0.1:9008", grpc.WithInsecure())
        if err != nil {
            log.Fatalln(err)
        }
        defer conn.Close()
    
        client := member.NewProfileServiceClient(conn)
        CreateMember(client)
        GetMember(client)
    }


    本文标题:grpc 在 golang 使用
    本文链接:https://www.lanseyujie.com/post/application-of-grpc-in-golang.html
    版权声明:本文使用「署名-非商业性使用-相同方式共享」创作共享协议,转载或使用请遵守署名协议。
    点赞 0 分享 0