RPC相关框架的使用方法

发布时间 2023-04-05 23:24:57作者: 来杯王老吉
1.go kratos gRPC使用

下面的代码gRPC官网的使用例子

定于proto文件用于服务器和客户端交互的方法,请求参数和返回结果。

syntax = "proto3";

option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (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;
}


1.proto文件用来定义消息格式,这是一种高效轻便的结构化数据存储方式,可以用于数据通信,数据储存。
2.protoBuf与xml,json一样都是存数据,用于传输的数据存储方式,不过protoBuf需要用生成器protoc生成对应语言的代码。
3.protoBuf是二进制传输,适合小文件传输,解析效率比较快。

proto和thrift都是IDL接口定义语言,进行RPC就需要对方的接口是什么,需要传什么,返回的值是什么,IDL就是来定义这个,客户端和服务端都要有,而且得同一个。

 

客户端代码

import pb "google.golang.org/grpc/examples/helloworld/helloworld"
type server struct {
    pb.UnimplementedGreeterServer
}

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
    //1.监听端口
    lis, err := net.Listen("tcp", "localhost:8080")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    //2.创建grpc服务
    s := grpc.NewServer()
    //3.将pb的服务信息和server结构体注册进grpc服务s
    pb.RegisterGreeterServer(s, &server{})
    //4.开启服务
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

 

先来看看运行逻辑
第三步就是 pb.RegisterGreeterServer(s, &server{})

相当于 s.RegisterService(&pb.Greeter_ServiceDesc, &server{})
将proto生成的Greeter_ServiceDesc 服务信息(方法和元数据等)和server结构体(待实现的方法)注册进grpc服务,这里用了两个map来保存methods,streams。

第二步跟第四步都是框架逻辑,后续再谈。

var Greeter_ServiceDesc = grpc.ServiceDesc{
    ServiceName: "helloworld.Greeter",
    HandlerType: (*GreeterServer)(nil),
    Methods: []grpc.MethodDesc{
        {
            MethodName: "SayHello",
            Handler:    _Greeter_SayHello_Handler,
        },
    },
    Streams:  []grpc.StreamDesc{},
    Metadata: "examples/helloworld/helloworld/helloworld.proto",
}

服务端代码

import  pb "google.golang.org/grpc/examples/helloworld/helloworld"

func main() {
    //1.拨号连接
    conn, err := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    //2.用pb创建客户端client
    c := pb.NewGreeterClient(conn)
    //3.创建ctx
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    //4.调用pb方法
    r, err := c.SayHello(ctx, &pb.HelloRequest{Name:"Name to greet"})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.GetMessage())
}

第一步连接服务器,生成grpc的ClientConn
第二步创建pb结构体,里面带有定义的方法,同时通过pb的初始化方法将grpc的ClientConn放到greeterClient
第三步调用方法
这样pb用ClientConn的invoke方法(grpc框架的方法)来执行要远程调用的方法。

func invoke(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, opts ...CallOption) error {
    cs, err := newClientStream(ctx, unaryStreamDesc, cc, method, opts...)
    if err != nil {
        return err
    }
    if err := cs.SendMsg(req); err != nil {
        return err
    }
    return cs.RecvMsg(reply)
}

 

2.go kitex

定义完IDL后

package main

import (
    "xx/echo"
    "xx/echo/echoservice"
)

type handler struct {}

func (handler) Echo(ctx context.Context, req *echo.Request) (r *echo.Response, err error) {
    //...
    return &echo.Response{ Msg: "world" }
}

func (handler) VisitOneway(ctx context.Context, req *echo.Request) (err error) {
    //...
    return nil
}

func main() {
    svr, err := echoservice.NewServer(handler{})
    if err != nil {
        panic(err)
    }
    svr.Run()
}

client

func main() {
    cli, err := echoservice.NewClient("destServiceName")
    if err != nil {
        panic(err)
    }
    req := echo.NewRequest()
    req.Msg = "hello"
    err = cli.VisitOneway(req)
    if err != nil {
        panic(err)
    }
}

引用链接:https://www.cloudwego.io/zh/docs/kitex/tutorials/basic-feature/message_type/

 

3. phpRPC

PHPRPC使用
server:
<?php
include ("phprpc/phprpc_server.php");
function HelloWorld() {
    return 'Hello World!';
}
$server = new PHPRPC_Server();
$server->add('HelloWorld');
$server->start();

client
<?php
include ("phprpc/phprpc_client.php");
$client = new PHPRPC_Client('http://127.0.0.1/server.php');
echo $client->HelloWorld();
?>

可以看到服务寻址是通过创建client stub(客户端存根)的时候写入的。

4.php yar

yar使用:
<?php
class API {
    public function api($parameter, $option = "foo") {
        return $parameter;
    }
    protected function client_can_not_see() {
    }
}
$service = new Yar_Server(new API());
$service->handle();

 

可以看到go-rpc框架的使用方法都类似,即将生成的结构体带上方法,加入到rpc框架里面,由框架来进行调用和返回。