grpc
gRPC 一開(kāi)始由 google 開(kāi)發(fā),開(kāi)源的遠(yuǎn)程過(guò)程調(diào)用(RPC)系統(tǒng)
grpc 支持同步和異步調(diào)用
簡(jiǎn)單模式下, 調(diào)用函數(shù)就像本地調(diào)用一樣, 直接傳輸數(shù)據(jù)
流式調(diào)用將信息以數(shù)據(jù)量的方式,發(fā)送或者接受,
gRPC 客戶端調(diào)用成功的判斷是獨(dú)立的本地的, 因此可能存在客戶端與服務(wù)端判斷不一致的情況
例如,您可以在服務(wù)器端成功完成RPC,但在客戶端失敗。在客戶端發(fā)送所有請(qǐng)求之前,服務(wù)器也可以決定完成
grpc是基于HTTP2協(xié)議的封裝
gRPC 請(qǐng)求和應(yīng)答消息流中一般的消息順序:
請(qǐng)求 → 請(qǐng)求報(bào)頭 *有定界符的消息 EOS
應(yīng)答 → 應(yīng)答報(bào)頭 *有定界符的消息 EOS
應(yīng)答 → (應(yīng)答報(bào)頭 *有定界符的消息 跟蹤信息) / 僅僅跟蹤時(shí)
proto文件
第一步是定義要在proto文件中序列化的數(shù)據(jù)的結(jié)構(gòu):這是一個(gè)帶.proto擴(kuò)展名的普通文本文件。協(xié)議緩沖區(qū)數(shù)據(jù)被構(gòu)造為 消息,其中每個(gè)消息是包含一系列稱為字段的名稱 - 值對(duì)的信息的邏輯記錄
message Person {
string name = 1;
int32 id = 2;
bool has_ponycopter = 3;
}
二.定義一個(gè)服務(wù), 指定其可以被遠(yuǎn)程調(diào)用的方法及其參數(shù)和返回類型
相當(dāng)于定義一個(gè)接口類型的服務(wù)
gRPC 默認(rèn)使用 protocol buffers 作為接口定義語(yǔ)言,來(lái)描述服務(wù)接口和有效載荷消息結(jié)構(gòu)
定義:
service HelloService {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
required string greeting = 1;
}
message HelloResponse {
required string reply = 1;
}
兩種類型調(diào)用
- 簡(jiǎn)單模式:
rpc SayHello(HelloRequest) returns (HelloResponse){
}
- 流式調(diào)用
- 服務(wù)端支持流式
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
}
- 客戶端支持流式:
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
}
- 雙向流式:雙方使用讀寫流發(fā)送一系列消息。這兩個(gè)流獨(dú)立運(yùn)行,因此客戶端和服務(wù)器可以按照自己喜歡的順序進(jìn)行讀寫:例如,服務(wù)器可以在寫入響應(yīng)之前等待接收所有客戶端消息,或者它可以交替地讀取消息然后寫入消息,或者其他一些讀寫組合
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
}
超時(shí):
grpc允許設(shè)置請(qǐng)求響應(yīng)超時(shí)時(shí)間:
參數(shù)為: DEADLINE_EXCEEDED
安全認(rèn)證:
grpc支持 SSL/TLS
支持OAuth 2.0
python:
備注: 示例可以參考
https://github.com/grpc/grpc/tree/master/examples/python
安裝:
pip install grpcio
pip install grpcio-tools # 安裝grpc工具
pip install grpcio-reflection #grpc-cli 調(diào)試工具
定義proto:
syntax = "proto3";
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 greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
rpc Square(Number) returns (Number) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
message Number {
float value = 1;
}
service 定義服務(wù), 實(shí)現(xiàn)接口功能定義
rpc xxx 為具體接口方法
編譯
定義完成后, 編譯轉(zhuǎn)換為python代碼:
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./rpc.proto
python_out和grpc_python_out 指定轉(zhuǎn)換服務(wù)端與客戶端的輸出文件
rpc.proto 指定proto文件
命令生成了兩個(gè)文件rpc_pb2.py 和rpc_pb2_grpc.py
實(shí)現(xiàn)server端:
from concurrent import futures
import logging
import math
import grpc
import time
import new_pb2
import new_pb2_grpc
def square(x):
return math.sqrt(x)
class Greeter(new_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return new_pb2.HelloReply(message='Hello, %s!' % request.name)
def Square(self, request, context):
x = square(request.value)
return new_pb2.Number(value=x)
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
new_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(1)
except:
print "exit"
# server.wait_for_termination()
if __name__ == '__main__':
logging.basicConfig()
serve()
實(shí)現(xiàn)client端:
from __future__ import print_function
import logging
import grpc
import new_pb2
import new_pb2_grpc
def run():
# NOTE(gRPC Python Team): .close() is possible on a channel and should be
# used in circumstances in which the with statement does not fit the needs
# of the code.
with grpc.insecure_channel('localhost:50051') as channel:
stub = new_pb2_grpc.GreeterStub(channel)
response = stub.SayHello(new_pb2.HelloRequest(name='you'))
print("Greeter client received: " + response.message)
res = stub.Square(new_pb2.Number(value=231))
print("client Square 231 get :" + str(res.value))
if __name__ == '__main__':
logging.basicConfig()
run()
輸出:
Greeter client received: Hello, you!
client Square 231 get :15.1986837387
文件操作
文件操作, 適用于小文件讀寫:
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.mux";
option java_outer_classname = "muxsProto";
option objc_class_prefix = "HLW";
package muxs;
service FileController {
rpc Read (Files) returns (Content) {}
rpc Write(Files) returns (Status) {}
}
message Content {
string text = 1;
}
message Files {
string filename = 1;
string text = 2;
}
message Status {
int64 code = 1;
}
在server端實(shí)現(xiàn):
class FileController(mux_pb2_grpc.FileControllerServicer):
def Read(self, request, context):
result = ""
filename = request.filename
try:
with open(filename) as fd:
for line in fd.readlines():
result += line
return mux_pb2.Content(text=result)
except:
return mux_pb2.Content(text="Error: read failed")
def Write(self, request, context):
filename = request.filename
file_contxt = request.text
try:
with open(filename, "wb") as fd:
fd.write(file_contxt)
fd.flush()
return mux_pb2.Status(code=0)
except:
return mux_pb2.Status(code=1)
serve
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
mux_pb2_grpc.add_FileControllerServicer_to_server(FileController(), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(1)
except:
print "exit"
client 客戶端實(shí)現(xiàn)調(diào)用:
def run():
channel = grpc.insecure_channel('localhost:50051')
stub = mux_pb2_grpc.GreeterStub(channel)
stub2 = mux_pb2_grpc.FileControllerStub(channel)
res2 = stub2.Read(mux_pb2.Files(filename="aaaa.txt", text=""))
print("File Read: " + res2.text)
res3 = stub2.Write(mux_pb2.Files(filename="aaaa2.txt", text="37183714ghgjh243"))
print("File Write: " + str(res3.code))
res2 = stub2.Read(mux_pb2.Files(filename="aaaa2.txt", text=""))
print("File Read: " + res2.text)
結(jié)果:
File Read: Error: read failed
File Write: 0
File Read: 37183714ghgjh243
可以將兩個(gè)服務(wù)合并, 一起定義在proto文件中:
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.mux";
option java_outer_classname = "muxsProto";
option objc_class_prefix = "HLW";
package muxs;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
rpc Square(Number) returns (Number) {}
}
service FileController {
rpc Read (Files) returns (Content) {}
rpc Write(Files) returns (Status) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
message Number {
float value = 1;
}
message Content {
string text = 1;
}
message Files {
string filename = 1;
string text = 2;
}
message Status {
int64 code = 1;
}
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
