玩转GRPC(2)-状态码

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 和Http协议一样,gRPC协议也提供了一组基础的状态码。 一般情况下,仅使用这组基础状态码就可以反应gPRC请求处理的所有错误信息。 2. 示例代码 grpc_status_error server var counter uint64 = 0 const ( port = ":50051" ) type server struct { pb.UnimplementedGreeterServer } // SayHello implements helloworld.GreeterServer func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { fmt.Println("pb.HelloRequest", in.Name) md, ok := metadata.FromIncomingContext(ctx) if !ok { fmt.Printf("get metadata error") } for key, val := range md { fmt.Printf("%v:%v\n", key, val) } x := atomic.AddUint64(&counter, 1) % 3 switch x { case 0: return &pb.HelloReply{Message: "Hello " + in.Name}, nil case 1: return nil, status.Error(codes.DataLoss, "--DataLoss--") default: return nil, status.Error(codes.Unauthenticated, "--Unauthenticated--") } } func main() { lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterGreeterServer(s, &server{}) // Register reflection service on gRPC server. reflection.Register(s) log.Println("say_hello_grpc starting...") if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } } client func main() { conn, err := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() client := pb.NewGreeterClient(conn) // Contact the server and print out its response. ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() r, err := client.SayHello(ctx, &pb.HelloRequest{Name: "lily"}) if err != nil { s := status.Convert(err) log.Printf("code:%v, message:%v\n", s.Code(), s.Message()) } else { log.Printf("reply:%v\n", r.String()) } } 也可以使用status.Code(err),直接得到code 当 err == nil 时,code为codes.OK, 值为0 3. wireshark 抓包 wireshark 抓包gRPC参考 Analyzing gRPC messages using Wireshark ...

February 5, 2024 · 2 min

介绍一个grpc记录和重放库 vearne/grpcreply-使用篇

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 引言 gRPC协议应用的非常广泛,针对它流量的记录和重放是一个非常常见的需求。但是到目前为止社区中都没有找到合适的库来实现这个目标。 终于它来了。传送门: vearne/grpcreplay 2.介绍 vearne/grpcreplay是一个网络监控工具,可以记录您的 grpc流量(Unary RPC),并将其用于灰度测试、压测或者流量分析。它有2大特点,使用简单,并且可以直接解析Protobuf的请求,并以JSON形式输出。 在使用vearne/grpcreplay前,你必须要知道vearne/grpcreplay的限制条件: 支持解析Unary RPC,不支持streaming RPC Server端必须开启反射 参考GRPC Server Reflection Protocol 3. 编译&使用 确保server所在的主机上已经安装了libpcap 安装libpcap可以参考以下命令: Ubuntu apt-get install libpcap-dev Centos yum install libpcap-devel Mac brew install libpcap 编译 make build 示例 server package main import ( "context" "encoding/json" "github.com/grpc-ecosystem/go-grpc-middleware" pb "github.com/vearne/grpcreplay/example/search_proto" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/reflection" "google.golang.org/grpc/status" "log" "net" "runtime/debug" "time" ) const PORT = "35001" type SearchServer struct{} func (s SearchServer) Search(ctx context.Context, in *pb.SearchRequest) (*pb.SearchResponse, error) { return &pb.SearchResponse{StaffID: 100, StaffName: in.StaffName}, nil } func (s SearchServer) CurrentTime(ctx context.Context, request *pb.TimeRequest) (*pb.TimeResponse, error) { return &pb.TimeResponse{CurrentTime: time.Now().Format(time.RFC3339)}, nil } func main() { opts := []grpc.ServerOption{ //grpc.Creds(c), grpc_middleware.WithUnaryServerChain( RecoveryInterceptor, LoggingInterceptor, ), //grpc.HeaderTableSize(0), //grpc.WithDisableRetry(), } server := grpc.NewServer(opts...) pb.RegisterSearchServiceServer(server, &SearchServer{}) // 注册反射服务(非常重要) // Register reflection service on gRPC server. reflection.Register(server) lis, err := net.Listen("tcp", ":"+PORT) if err != nil { log.Fatalf("net.Listen err: %v", err) } server.Serve(lis) } func LoggingInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { log.Printf("gRPC method: %s, %v", info.FullMethod, req) resp, err := handler(ctx, req) bt, _ := json.Marshal(req) log.Println("body", string(bt)) log.Printf("gRPC method: %s, %v", info.FullMethod, resp) return resp, err } func RecoveryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { defer func() { if e := recover(); e != nil { debug.PrintStack() err = status.Errorf(codes.Internal, "Panic err: %v", e) } }() return handler(ctx, req) } client ...

October 17, 2022 · 2 min

grpc的反射机制

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 读者们可能使用过 fullstorydev/grpcurl 来对grpc服务进行调用调试。 假定有一个简单的grpc的服务 main.go package main import ( "context" "log" "net" "google.golang.org/grpc" pb "google.golang.org/grpc/examples/helloworld/helloworld" "google.golang.org/grpc/reflection" ) const ( port = ":50051" ) // server is used to implement helloworld.GreeterServer. type server struct { pb.UnimplementedGreeterServer } // SayHello implements helloworld.GreeterServer func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { log.Printf("Received: %v", in.GetName()) return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil } func main() { lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() helloService := &server{} pb.RegisterGreeterServer(s, helloService) // 注册反射服务 // Register reflection service on gRPC server. reflection.Register(s) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } } 使用grpcurl来请求grpc服务 ...

May 11, 2021 · 2 min

一个简单的陌生人聊天系统

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 前言 因为一直对IM的实现非常感兴趣,前段时间也自己手撸了一个。 萌叔觉得,这个版本实现比较简单,但能够从部分反映出IM的概貌,可能会其他的朋友有所帮助, 因此决定分享出来。 1. 功能说明 这个聊天系统被设计为陌生人自动匹配进行聊天,因此不需要注册。分为2个模块,在线体验地址 chat.vearne.cc 备注:如果匹配不上,可以多开几个窗口,自己和自己聊 1.1 客户端 vearne/chat-ui 客户端采用Vue开发 依赖组件 MatheusrdSantos/vue-quick-chat 1.2 服务端 vearne/chat 采用golang开发 重要框架 olahol/melody – websocket框架 grpc/grpc-go – grpc框架 架构图 客户与接入层的通讯采用websocket + 自定义的文本协议实现。 自定义的协议其实都是携带着各种命令的JSON字符串,很容易看懂 比如 创建一个新的账号(由客户端发出) request { "cmd": "CRT_ACCOUNT", "nickName": "XXXX" } response { "cmd": "CRT_ACCOUNT", "nickName": "XXXX", "accountId": 1111 } 又比如 匹配一个聊天对象 request { "cmd": "MATCH", "accountId": 1111 } response { "cmd": "MATCH", "partnerId": 1111, "partnerName": "xxxx", "sessionId": 10000 "code": 0 } 具体请看github相关页面 ...

December 19, 2019 · 1 min

玩转GRPC(1)-整合JSON编码方式

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 引言 提到GRPC大家想到的就是 HTTP2 + protobuf。HTTP2能够实现多路复用, protobuf提高数据传输的压缩率。但其实GRPC还可以跟Thrift、JSON等编码方式进行整合。 gRPC lets you use encoders other than Protobuf. It has no dependency on Protobuf and was specially made to work with a wide variety of environments. We can see that with a little extra boilerplate, we can use any encoder we want. While this post only covered JSON, gRPC is compatible with Thrift, Avro, Flatbuffers, Cap’n Proto, and even raw bytes! gRPC lets you be in control of how your data is handled. (We still recommend Protobuf though due to strong backwards compatibility, type checking, and performance it gives you.) ...

September 2, 2019 · 3 min