GRPCの概要
grpcはgoogleが提供するrpc呼び出しメソッドであり、googleのprotobuf定義メソッドに基づいており、データ定義とrpc送信メソッドの完全なセットを提供します。この段階では、grpcは完全ではなく、一部の機能はまだ使用できません。
RPCの紹介
grpcを導入する前に、まずrpcを導入する必要があります。RPCの完全な英語名はRemote Procedure Callで、リモート関数またはメソッドのローカル呼び出しを実装します。これはメモリ空間になく、直接呼び出すことはできないため、呼び出しのセマンティクスを表現し、ネットワークを介して呼び出しのデータを伝達する必要があります。基本的なプロセスを次の図に示します。
クライアントはリモート関数を呼び出す必要があります。まず、クライアントスタブで関数のセマンティクスとデータのネットワーク式を実行する必要があります。次に、エスケープされたデータがソケットを介してネットワークを介してサーバーに送信され、その後、リモートサービスがサーバースタブの分析を介して呼び出されます。関数。関数の結果は、同じリンクを介してクライアントに返されます。
Protobufの概要
以前にprotobufの詳細な紹介があります:https ://blog.csdn.net/a40850273/article/details/90482546 。
Protobufは、Googleが提供する汎用的なデータ表現方法です。protoファイルで定義されたデータ形式を介して、C ++、Python、Javaなどのさまざまな言語でワンクリックで実装できます。学生クラスの例を以下に示します。
syntax = "proto3"; // 指定基于 protobuf 3 协议
package general_match; // 指定对应的包名
message Student {
int32 id = 1; // 定义 int32 类型的成员变量,变量名为 id
double time = 2; // 定义 double 类型的成员变量,变量名为 time
string name = 3; // 定义 string 类型的成员变量,变量名为 name
repeated double score = 4; // 定义一个 double 的数组,变量名为 score
}
protocツールを使用して、書き込まれたprotobufファイルを指定した言語のヘッダーファイルまたはソースファイルにコンパイルできます。オンラインでダウンロードした後、次のコマンドを直接使用してprotobufファイルをコンパイルできます。
protoc --python_out=./ student.proto
この例はpythonファイルとしてコンパイルされています。他の言語にコンパイルする必要がある場合は、下の図を参照してください。
生成された*** _ pb2.pyファイルは、主にprotobufで定義されたデータ型であり、直接参照することができます。
GRPCの概要
grpcは、基本的なprotobufファイルにrpc呼び出しメソッドを指定するための指示を追加します。基本的な形は以下の通りです。
syntax = "proto3";
package example;
message BytesData { // 定义了一个二进制的数据格式
int32 size = 1;
bytes data = 2;
}
service Test { // 定义了一个名为 Test 的服务
rpc test(BytesData) returns (BytesData) {} // 提供了一个名为 test 远程调用函数
}
一般的な実装方法は上記のとおりです。複雑な入力および出力パラメーターの場合、例のシリアル化および非シリアル化メソッドを使用して定義できます。デフォルトのシリアル化および非シリアル化を実装しないデータ構造またはカスタマイズの場合データ構造は自分で定義する必要があります。もちろん、protobufでデータ型を定義する例を参照して、クラスの各変数を具体的に定義することもできます。
rpc定義が追加されたprotobufファイルは、上記のprotocコンパイル方法を使用できなくなります。protocは、その一般的な部分のみをコンパイルできます。つまり、ファイル名_pb2.pyファイルのみが出力され、リモート呼び出しのファイル名_pb2_grpcは出力されません。 py(ここではpythonを例にとります)。具体的なコンパイル方法は以下の通りです。
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. example.proto
コンパイルする前に、grpc_toolsのpythonライブラリをインストールする必要があります(ここでは、例としてpythonを取り上げます)。ここで、-Iは入力ファイルの場所を指定し、-python_outは一般的なprotobufファイルの出力場所を指定し、-grpc_python_outはgrpcファイルの出力場所を指定します。
このうち、**** _ pb2_grpc.pyファイルには、主に2つのクラスと1つのメソッドが含まれています。
- TestStubクラス:Testはprotobufで定義されたサービス名であり、リモート関数を呼び出すことができる基本クラスをインスタンス化するためにクライアントによって使用されます
- TestServicerクラス:サーバー側でカスタムサービスクラスを記述するための基本クラスとして
- function add_TestServicer_to_server:サーバー側のカスタム基本クラスを指定されたサービスとして登録します
GRPCクライアントとサーバー側の記述(Pythonバージョン)
次のステップは、生成されたexample_pb2.pyおよびexample_pb2_grpc.pyファイルに基づいて、サーバー側およびクライアント側のコードを記述することです。
サーバー側のコード例。
#!/usr/bin/env python
# encoding: utf8
from __future__ import print_function
import grpc
import example_pb2_grpc
import example_pb2
import utils_pb2
class MyServicer(example_pb2_grpc.TestServicer): # 继承自动生成的 grpc 文件中的 Servicer 类
def test(self, request, context): # 实现指定的 test 调用函数,输入参数固定
img_str = request.data[:request.size] # request 传入为 protobuf 文件中定义的输入数据
img = cv2.imdecode(np.fromstring(img_str, dtype=np.uint8), cv2.IMREAD_COLOR) # 根据实际情况,反序列化数据,这里以图片为例
out = img_process(img) # 调用本地的处理函数,生成处理结果
return out
def serve(): # 启动服务端程序
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
example_pb2_grpc.add_TestServicer_to_server(MyServicer(), server) # 调用默认生成的 add_TestServicer_to_server 函数
server.add_insecure_port('[::]:40051') # 指定一个端口号,这里为 40051
server.start()
server.wait_for_termination()
if __name__ == '__main__':
serve()
この例のMyServicerは、それ自体で指定されたリモートサービスクラス名です。TestServicerは、対応するprotobufファイルで指定されたサービステストサービスであり、rpc呼び出しを満たすServicerサフィックスによって生成されたサービス基本クラス名を自動的に追加します。サービスのスタートアップによって呼び出されるadd_TestServicer_to_server関数も、TestServicerの自動組み合わせによって生成されます。
クライアントのコード例。
#!/usr/bin/env python
# encoding: utf8
from __future__ import print_function
import example_pb2_grpc
import example_pb2
import grpc
class MyClient(object):
def __init__(self, server_ip="127.0.0.1:40051"):
self.channel = grpc.insecure_channel(server_ip) # 指定远端服务的 ip 和端口号
self.stub = example_pb2_grpc.TestStub(self.channel) # 调用自动生成的 TestStub 基类
def test(self, img):
img_str = cv2.imencode(".png", img)[1].tostring()
out = self.stub.test(example_pb2.BytesData(size=len(img_str), data=img_str)) # 通过 TestStub 基类对象调用远程服务
return out
def main():
client = MyClient("127.0.0.1:40051")
out = client.test("test.jpg")
if __name__ == '__main__':
main()
この例のMyClientは、それ自体で指定されたローカルサービスクラスの名前です。TestStubは、対応するprotobufファイルで指定されたサービスTestサービスです。rpc呼び出しを満たすスタブサフィックスによって生成されたクライアント基本クラス名を自動的に追加し、基本クラスによって生成されたオブジェクトを介して、protobufファイルで定義されたリモート呼び出し関数を呼び出すことができます。
その他の問題処理
GRPCコールで個人が遭遇する問題のいくつか、および特定の解決策を以下に要約します。
1.リモート呼び出し関数定義の複数の入力および出力パラメーターエラー
具体的な理由は、この段階ではgrpcが単一の入力および出力パラメーターのみをサポートするためです。リモート呼び出し入力として使用できるprotobufのデータ型をカスタマイズすることにより、複数のパラメーターを1つのパラメーターに結合できます。
2.通話中に、grpcを要求します:最大より大きい受信メッセージ(8653851と4194304)
具体的な理由は、grpcのデフォルトの送信パラメーターサイズが4M(4 * 1024 * 1024 = 4194304)であるためです。このとき、入力パラメーターと出力パラメーターが大きすぎると、エラーが報告されます。具体的には、以下のようにパラメータメモリサイズを自分で指定できます。
options = [('grpc.max_send_message_length', 100 * 1024 * 1024),
('grpc.max_receive_message_length', 100 * 1024 * 1024)]
self.channel = grpc.insecure_channel(server_ip, options=options)