GRPC 鏈接 NODE 和 GOLANG
GRPC 了解
什么是GRPC
- gRPC 采用了
Protocol Buffers 作為數據序列化和反序列化的協議
,可以更快速地傳輸數據,并支持多種編程語言的跨平臺使用 - gRPC 提供
“統一水平層”
來對此類問題進行抽象化。 開發人員在本機平臺中編寫專注于業務功能的代碼,而 gRPC 會處理通信管道。
優勢
RPC 使用 HTTP/2 作為傳輸協議。 雖然與 HTTP 1.1 也能兼容,但 HTTP/2 具有許多高級功能:
用于數據傳輸的二進制組幀協議 - 與 HTTP 1.1 不同,HTTP 1.1 是基于文本的。
- 對通過同一連接發送多個并行請求的多路復用支持 - HTTP 1.1 將處理限制為一次處理一個請- 求/響應消息。
- 雙向全雙工通信,用于同時發送客戶端請求和服務器響應。
- 內置流式處理,支持對大型數據集進行異步流式處理的請求和響應。
- 減少網絡使用率的標頭壓縮。
- 其處理速度可以比 JSON 序列化快 8 倍,消息小 60% 到 80%
解決什么問題
- 高效處理 不同語言端的通信。 約定協議多端 對自定義的IDL 各自單獨實現
Proto 文件生成Go 代碼
- 在propto 文件夾下創建 helloworld.proto 文件
syntax = "proto3";
// option go_package = "./yp-tpl/proto";
option go_package = "./";option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";package helloworld;// The greeting service definition.
service Greeter {// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply) {}rpc SayHelloStreamReply (HelloRequest) returns (stream HelloReply) {}
}// The request message containing the user's name.
message HelloRequest {string name = 1;
}// The response message containing the greetings
message HelloReply {string message = 1;
}
- 使用腳本命令 生成 go文件
protoc --go_out=. --go_opt=paths=source_relative \--go-grpc_out=. --go-grpc_opt=paths=source_relative \./proto/*.proto
會生成 這兩個文件
server (golang)
package mainimport ("context""flag""fmt""log""net"pb "yp-tpl/proto" // 相對路徑引用proto文件"google.golang.org/grpc"
)var (port = flag.Int("port", 50051, "The server port")
)// 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 123" + in.GetName()}, nil
}func start() {flag.Parse()lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))if err != nil {log.Fatalf("failed to listen: %v", err)}s := grpc.NewServer()pb.RegisterGreeterServer(s, &server{})log.Printf("server listening at %v", lis.Addr())if err := s.Serve(lis); err != nil {log.Fatalf("failed to serve: %v", err)}
}
client (golang)
package mainimport ("context""flag""log""time"pb "yp-tpl/proto" // 相對路徑引用proto文件"google.golang.org/grpc""google.golang.org/grpc/credentials/insecure"
)const (defaultName = "world"
)var (addr = flag.String("addr", "localhost:50051", "the address to connect to")name = flag.String("name", defaultName, "Name to greet")
)func main() {flag.Parse()// Set up a connection to the server.conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Fatalf("did not connect: %v", err)}defer conn.Close()c := pb.NewGreeterClient(conn)// Contact the server and print out its response.ctx, cancel := context.WithTimeout(context.Background(), time.Second)defer cancel()r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name})if err != nil {log.Fatalf("could not greet: %v", err)}log.Printf("Greeting: %s", r.GetMessage())
}
client (Node)
import grpc from '@grpc/grpc-js';
import protoLoader from '@grpc/proto-loader';
import path from 'node:path';const currentPath = new URL(import.meta.url).pathname;
//路徑
const PROTO_PATH = path.join(currentPath, '../../../yp-tpl/proto/helloworld.proto');
console.log(PROTO_PATH);const client = () => {var packageDefinition = protoLoader.loadSync(PROTO_PATH,{keepCase: true,longs: String,enums: String,defaults: true,oneofs: true});var help_proto = grpc.loadPackageDefinition(packageDefinition).helloworld;var client = new help_proto.Greeter('localhost:50051', grpc.credentials.createInsecure());return client;
};export default client//== 調用時const client = await grpc();client.sayHello({ name: "asd" }, function (err, response) {console.log('==>>Greeting:', response.message);});
參考資料
- microsoft GRPC
- https://grpc.io/