1 hello.proto

syntax = "proto3"; // 声明使用哪一种的protobuf

package test; // 包名称

// 服务 类似视图
service Bibili {
    // rpc 服务
    rpc HelloYoyo (HelloYoyoRequst) returns (HelloYoyoResponse) {
    }
    rpc HelloTest (HelloTsetRquest) returns (HelloTestRsponse) {
    }
    rpc HelloStream (stream HelloTsetRquest) returns (stream HelloTestRsponse) { // 定义流传输
    }
    rpc TsetClientRectStream (TsetClientRectStreamRequest) returns (stream TsetClientRectStreamRsponse) {
    }
    rpc TsetClientSendStream (stream TsetClientSendStreamRequest) returns (TsetClientSendStreamRsponse) {
    }
    rpc TsetTowWayStream (stream TsetTowWayStreamRquest) returns (stream TsetTowWayStreamRsponse) {
    }
}

message TsetTowWayStreamRquest {
    string data = 1;
}

message TsetTowWayStreamRsponse {
    string result = 1;
}

message TsetClientSendStreamRequest {
    string data = 1;
}

message TsetClientSendStreamRsponse {
    string result = 1;
}

message TsetClientRectStreamRequest {
    string data = 1;
}

message TsetClientRectStreamRsponse {
    string result = 1;
}

message HelloYoyoRequst {
    string name = 1;
    int32 age = 2;
}

message HelloYoyoResponse {
    string result = 1;
}

message HelloTsetRquest {
    string name = 1;
    int32 age = 2;
    repeated string data = 3;
    repeated HelloTsetRsqusetValue lists = 4; // 自己定义数据类型
    map<string, int64> number = 5; //注释
    map<string, HelloTsetRsqusetValue> value = 6; // 自己定义数据类型
}

message HelloTsetRsqusetValue {
    string name = 1;
    int32 age = 2;
    bool is_active = 3;
}


message HelloTestRsponse {
}

2 service.py

import time
from concurrent import futures  # grcp线程

import grpc

import hello_pb2 as pb2
import hello_pb2_grpc as pb2_grcp


def _abort(code, detail):
    def terminate(ingnored_request, context):
        context.abort(code, detail)

    return grpc.unary_unary_rpc_method_handler(terminate)


# 书写一个拦截器
class TestInterceptor(grpc.ServerInterceptor):
    def __init__(self, key, value, code, detail):
        self.key = key
        self.value = value
        self._abort = _abort(code, detail)

    def intercept_service(self, continuation, handler_call_details):
        '''
        :param continuation:  函数执行器
        :param handler_call_details: header
        :return:
        '''
        if (self.key, self.value) not in handler_call_details.invocation_metadata:
            return self._abort

        return continuation(handler_call_details)


class Bibili(pb2_grcp.BibiliServicer):
    def HelloYoyo(self, request, context):
        name = request.name
        age = request.age
        if name == "yoyo123":
            context.set_details("程序出现问题")  # 添加一些描述
            context.set_code(grpc.StatusCode.DATA_LOSS)  # 设置code码
            raise context  # 抛出异常
        context.set_trailing_metadata((("name", "yoyo"), ("key", "vlaue")))  # 给客户端传输消息
        headers = context.invocation_metadata()  # 接受客户端传输过来的消息
        print(headers)
        print(headers[0].key, headers[0].value)
        result = "my name is {}, i am {} year old".format(name, age)
        context.set_compression(grpc.Compression.Gzip)  # 数据压缩 只针对这个函数内的内容
        return pb2.HelloYoyoResponse(result=result)

    def TsetClientRectStream(self, request, context):
        index = 0
        while context.is_active():
            data = request.data
            if data == 'close':
                print('data is close, request will cancel')
                context.cancel()  # 关闭

            time.sleep(1)
            index += 1
            yield pb2.TsetClientRectStreamRsponse(result="send{}: {}".format(index, data))

    def TsetClientSendStream(self, request_iterator, context):
        index = 0
        for request in request_iterator:
            print(request.data)
            if index == 10:
                break
            index += 1
        return pb2.TsetClientSendStreamRsponse(result="ok")

    def TsetTowWayStream(self, request_iterator, context):
        index = 0
        for request in request_iterator:
            data = request.data
            print(data)
            if index == 10:
                context.cancel()  # 关闭
            index += 1
            yield pb2.TsetTowWayStreamRsponse(result="service send {}".format(data))


def run():
    validator = TestInterceptor("name", "yoyo", grpc.StatusCode.UNAUTHENTICATED, "Access denined")
    grpc_server = grpc.server(
        futures.ThreadPoolExecutor(max_workers=4),  # 设置工作时最大的线程数量
        compression=grpc.Compression.Gzip,  # 设置压缩, 针对这个服务器所有的内容
        interceptors=(validator,),
        options=[("grpc.max_send_message_length", 50 * 1024 * 1024),  # grpc.max_send_message_length:设置发送数据的最大数量
                 ("grpc.max_receive_message_length", 50 * 1024 * 2014)]  # grpc.max_receive_message_length:设置接收数据的最大数量
    )

    pb2_grcp.add_BibiliServicer_to_server(Bibili(), grpc_server)  # 注册Bibili到grpc_server中
    grpc_server.add_insecure_port("0.0.0.0:5000")  # 绑定ip和端口
    print("server will start at 0.0.0.0:5000")
    grpc_server.start()  # 启动

    try:
        while 1:
            time.sleep(3600)  # 堵塞在这里
    except KeyboardInterrupt:
        grpc_server.stop(0)  # 结束


if __name__ == "__main__":
    run()

3 client.py

import random
import time

import grpc

import hello_pb2 as pb2
import hello_pb2_grpc as pb2_grpc


def test():
    index = 0
    while True:
        time.sleep(1)
        data = str(random.random())
        if index == 5:
            break
        index += 1
        yield pb2.TsetClientSendStreamRequest(data=data)


def run():
    conn = grpc.insecure_channel("0.0.0.0:5000")  # 定义一个频道
    client = pb2_grpc.BibiliStub(channel=conn)  # 生成客户端
    try:
        response, call = client.HelloYoyo.with_call(pb2.HelloYoyoRequst(name="yoyo", age=33), compression=grpc.Compression.Gzip, wait_for_ready=True, metadata=(("clicent_key", "client_value"),))  # metadata 给服务器传输消息   grpc.Compression.Gzip:压缩数据
        print(response.result)
        headers = call.trailing_metadata()  # 接受服务器传输过来的消息
        print(headers)
        print(headers[0].key, headers[0].value)
        # print(help(client.HelloYoyo.with_call))
    except Exception as e:
        print(dir(e))  # 查看对像内所有属于及方法
        print(e.code(), e.code().name, e.code().value)
        print(e.details())

    # response = client.TsetClientRectStream(pb2.TsetClientRectStreamRequest(data='yoyo'))
    # for item in response:
    #     print(item.result)

    # response = client.TsetClientSendStream(test())
    # print(response.result)

    # response = client.TsetTowWayStream(test(), timeout=10)  # 请求超时时长
    # for request in response:
    #     print(request.result)


if __name__ == "__main__":
    run()