Merge pull request #19938 from kerbalwzy/master
Add a quick-start example for basic usages in Pythonpull/20256/head
commit
5931fde9c7
7 changed files with 650 additions and 0 deletions
@ -0,0 +1,36 @@ |
|||||||
|
## Data transmission demo for using gRPC in Python |
||||||
|
|
||||||
|
在Python中使用gRPC时, 进行数据传输的四种方式 [官方指南](<https://grpc.io/docs/guides/concepts/#unary-rpc>) |
||||||
|
|
||||||
|
- #### 一元模式 |
||||||
|
|
||||||
|
在一次调用中, 客户端只能向服务器传输一次请求数据, 服务器也只能返回一次响应 |
||||||
|
|
||||||
|
`client.py - line:14 - simple_method` |
||||||
|
|
||||||
|
`server.py - line:17 - SimpleMethod` |
||||||
|
|
||||||
|
- #### 客户端流模式 |
||||||
|
|
||||||
|
在一次调用中, 客户端可以多次向服务器传输数据, 但是服务器只能返回一次响应 |
||||||
|
|
||||||
|
`clien.py - line:27 - client_streaming_method ` |
||||||
|
|
||||||
|
`server.py - line:28 - ClientStreamingMethod` |
||||||
|
|
||||||
|
- #### 服务端流模式 |
||||||
|
|
||||||
|
在一次调用中, 客户端只能向服务器传输一次请求数据, 但是服务器可以多次返回响应 |
||||||
|
|
||||||
|
`clien.py - line:48 - server_streaming_method` |
||||||
|
|
||||||
|
`server.py - line:41 - ServerStreamingMethod` |
||||||
|
|
||||||
|
- #### 双向流模式 |
||||||
|
|
||||||
|
在一次调用中, 客户端和服务器都可以向对方多次收发数据 |
||||||
|
|
||||||
|
`client.py - line:63 - bidirectional_streaming_method` |
||||||
|
|
||||||
|
`server.py - line:59 - BidirectionalStreamingMethod` |
||||||
|
|
@ -0,0 +1,37 @@ |
|||||||
|
## Data transmission demo for using gRPC in Python |
||||||
|
|
||||||
|
Four ways of data transmission when gRPC is used in Python. [Offical Guide](<https://grpc.io/docs/guides/concepts/#unary-rpc>) |
||||||
|
|
||||||
|
- #### unary-unary |
||||||
|
|
||||||
|
In a single call, the client can only send request once, and the server can only respond once. |
||||||
|
|
||||||
|
`client.py - line:14 - simple_method` |
||||||
|
|
||||||
|
`server.py - line:17 - SimpleMethod` |
||||||
|
|
||||||
|
- #### stream-unary |
||||||
|
|
||||||
|
In a single call, the client can transfer data to the server an arbitrary number of times, but the server can only return a response once. |
||||||
|
|
||||||
|
`clien.py - line:27 - client_streaming_method` |
||||||
|
|
||||||
|
`server.py - line:28 - ClientStreamingMethod` |
||||||
|
|
||||||
|
- #### unary-stream |
||||||
|
|
||||||
|
In a single call, the client can only transmit data to the server at one time, but the server can return the response many times. |
||||||
|
|
||||||
|
`clien.py - line:48 - server_streaming_method` |
||||||
|
|
||||||
|
`server.py - line:41 - ServerStreamingMethod` |
||||||
|
|
||||||
|
- #### stream-stream |
||||||
|
|
||||||
|
In a single call, both client and server can send and receive data |
||||||
|
to each other multiple times. |
||||||
|
|
||||||
|
`client.py - line:63 - bidirectional_streaming_method` |
||||||
|
|
||||||
|
`server.py - line:59 - BidirectionalStreamingMethod` |
||||||
|
|
@ -0,0 +1,114 @@ |
|||||||
|
# Copyright 2019 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
"""The example of four ways of data transmission using gRPC in Python.""" |
||||||
|
|
||||||
|
import time |
||||||
|
import grpc |
||||||
|
|
||||||
|
import demo_pb2_grpc |
||||||
|
import demo_pb2 |
||||||
|
|
||||||
|
SERVER_ADDRESS = "localhost:23333" |
||||||
|
CLIENT_ID = 1 |
||||||
|
|
||||||
|
|
||||||
|
# 一元模式(在一次调用中, 客户端只能向服务器传输一次请求数据, 服务器也只能返回一次响应) |
||||||
|
# unary-unary(In a single call, the client can only send request once, and the server can |
||||||
|
# only respond once.) |
||||||
|
def simple_method(stub): |
||||||
|
print("--------------Call SimpleMethod Begin--------------") |
||||||
|
request = demo_pb2.Request( |
||||||
|
client_id=CLIENT_ID, request_data="called by Python client") |
||||||
|
response = stub.SimpleMethod(request) |
||||||
|
print("resp from server(%d), the message=%s" % (response.server_id, |
||||||
|
response.response_data)) |
||||||
|
print("--------------Call SimpleMethod Over---------------") |
||||||
|
|
||||||
|
|
||||||
|
# 客户端流模式(在一次调用中, 客户端可以多次向服务器传输数据, 但是服务器只能返回一次响应) |
||||||
|
# stream-unary (In a single call, the client can transfer data to the server several times, |
||||||
|
# but the server can only return a response once.) |
||||||
|
def client_streaming_method(stub): |
||||||
|
print("--------------Call ClientStreamingMethod Begin--------------") |
||||||
|
|
||||||
|
# 创建一个生成器 |
||||||
|
# create a generator |
||||||
|
def request_messages(): |
||||||
|
for i in range(5): |
||||||
|
request = demo_pb2.Request( |
||||||
|
client_id=CLIENT_ID, |
||||||
|
request_data=("called by Python client, message:%d" % i)) |
||||||
|
yield request |
||||||
|
|
||||||
|
response = stub.ClientStreamingMethod(request_messages()) |
||||||
|
print("resp from server(%d), the message=%s" % (response.server_id, |
||||||
|
response.response_data)) |
||||||
|
print("--------------Call ClientStreamingMethod Over---------------") |
||||||
|
|
||||||
|
|
||||||
|
# 服务端流模式(在一次调用中, 客户端只能一次向服务器传输数据, 但是服务器可以多次返回响应) |
||||||
|
# unary-stream (In a single call, the client can only transmit data to the server at one time, |
||||||
|
# but the server can return the response many times.) |
||||||
|
def server_streaming_method(stub): |
||||||
|
print("--------------Call ServerStreamingMethod Begin--------------") |
||||||
|
request = demo_pb2.Request( |
||||||
|
client_id=CLIENT_ID, request_data="called by Python client") |
||||||
|
response_iterator = stub.ServerStreamingMethod(request) |
||||||
|
for response in response_iterator: |
||||||
|
print("recv from server(%d), message=%s" % (response.server_id, |
||||||
|
response.response_data)) |
||||||
|
|
||||||
|
print("--------------Call ServerStreamingMethod Over---------------") |
||||||
|
|
||||||
|
|
||||||
|
# 双向流模式 (在一次调用中, 客户端和服务器都可以向对方多次收发数据) |
||||||
|
# stream-stream (In a single call, both client and server can send and receive data |
||||||
|
# to each other multiple times.) |
||||||
|
def bidirectional_streaming_method(stub): |
||||||
|
print( |
||||||
|
"--------------Call BidirectionalStreamingMethod Begin---------------") |
||||||
|
|
||||||
|
# 创建一个生成器 |
||||||
|
# create a generator |
||||||
|
def request_messages(): |
||||||
|
for i in range(5): |
||||||
|
request = demo_pb2.Request( |
||||||
|
client_id=CLIENT_ID, |
||||||
|
request_data=("called by Python client, message: %d" % i)) |
||||||
|
yield request |
||||||
|
time.sleep(1) |
||||||
|
|
||||||
|
response_iterator = stub.BidirectionalStreamingMethod(request_messages()) |
||||||
|
for response in response_iterator: |
||||||
|
print("recv from server(%d), message=%s" % (response.server_id, |
||||||
|
response.response_data)) |
||||||
|
|
||||||
|
print("--------------Call BidirectionalStreamingMethod Over---------------") |
||||||
|
|
||||||
|
|
||||||
|
def main(): |
||||||
|
with grpc.insecure_channel(SERVER_ADDRESS) as channel: |
||||||
|
stub = demo_pb2_grpc.GRPCDemoStub(channel) |
||||||
|
|
||||||
|
simple_method(stub) |
||||||
|
|
||||||
|
client_streaming_method(stub) |
||||||
|
|
||||||
|
server_streaming_method(stub) |
||||||
|
|
||||||
|
bidirectional_streaming_method(stub) |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
main() |
@ -0,0 +1,69 @@ |
|||||||
|
// Copyright 2019 gRPC authors. |
||||||
|
// |
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
// you may not use this file except in compliance with the License. |
||||||
|
// You may obtain a copy of the License at |
||||||
|
// |
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
// |
||||||
|
// Unless required by applicable law or agreed to in writing, software |
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
// See the License for the specific language governing permissions and |
||||||
|
// limitations under the License. |
||||||
|
|
||||||
|
// 语法版本声明,必须放在非注释的第一行 |
||||||
|
// Syntax version declaration. Must be placed on the first line of non-commentary. |
||||||
|
|
||||||
|
syntax = "proto3"; |
||||||
|
// The document of proto3: https://developers.google.com/protocol-buffers/docs/proto3 |
||||||
|
|
||||||
|
// 包名定义, Python中使用时可以省略不写 |
||||||
|
// Package name definition, which can be omitted in Python. |
||||||
|
package demo; |
||||||
|
|
||||||
|
/* |
||||||
|
`message`是用来定义传输的数据的格式的, 等号后面的是字段编号 |
||||||
|
消息定义中的每个字段都有唯一的编号 |
||||||
|
总体格式类似于Python中定义一个类或者Golang中定义一个结构体 |
||||||
|
*/ |
||||||
|
/* |
||||||
|
`message` is used to define the structure of the data to be transmitted, after the equal sign |
||||||
|
is the field number. Each field in the message definition has a unique number. |
||||||
|
The overall format is similar to defining a class in Python or a structure in Golang. |
||||||
|
*/ |
||||||
|
message Request { |
||||||
|
int64 client_id = 1; |
||||||
|
string request_data = 2; |
||||||
|
} |
||||||
|
|
||||||
|
message Response { |
||||||
|
int64 server_id = 1; |
||||||
|
string response_data = 2; |
||||||
|
} |
||||||
|
|
||||||
|
// `service` 是用来给gRPC服务定义方法的, 格式固定, 类似于Golang中定义一个接口 |
||||||
|
// `service` is used to define methods for gRPC services in a fixed format, similar to defining |
||||||
|
//an interface in Golang |
||||||
|
service GRPCDemo { |
||||||
|
// 一元模式(在一次调用中, 客户端只能向服务器传输一次请求数据, 服务器也只能返回一次响应) |
||||||
|
// unary-unary(In a single call, the client can only send request once, and the server can |
||||||
|
// only respond once.) |
||||||
|
rpc SimpleMethod (Request) returns (Response); |
||||||
|
|
||||||
|
// 客户端流模式(在一次调用中, 客户端可以多次向服务器传输数据, 但是服务器只能返回一次响应) |
||||||
|
// stream-unary (In a single call, the client can transfer data to the server several times, |
||||||
|
// but the server can only return a response once.) |
||||||
|
rpc ClientStreamingMethod (stream Request) returns (Response); |
||||||
|
|
||||||
|
// 服务端流模式(在一次调用中, 客户端只能一次向服务器传输数据, 但是服务器可以多次返回响应) |
||||||
|
// unary-stream (In a single call, the client can only transmit data to the server at one time, |
||||||
|
// but the server can return the response many times.) |
||||||
|
rpc ServerStreamingMethod (Request) returns (stream Response); |
||||||
|
|
||||||
|
// 双向流模式 (在一次调用中, 客户端和服务器都可以向对方多次收发数据) |
||||||
|
// stream-stream (In a single call, both client and server can send and receive data |
||||||
|
// to each other multiple times.) |
||||||
|
rpc BidirectionalStreamingMethod (stream Request) returns (stream Response); |
||||||
|
} |
||||||
|
|
@ -0,0 +1,174 @@ |
|||||||
|
# -*- coding: utf-8 -*- |
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||||
|
# source: demo.proto |
||||||
|
|
||||||
|
import sys |
||||||
|
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) |
||||||
|
from google.protobuf import descriptor as _descriptor |
||||||
|
from google.protobuf import message as _message |
||||||
|
from google.protobuf import reflection as _reflection |
||||||
|
from google.protobuf import symbol_database as _symbol_database |
||||||
|
# @@protoc_insertion_point(imports) |
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default() |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor.FileDescriptor( |
||||||
|
name='demo.proto', |
||||||
|
package='demo', |
||||||
|
syntax='proto3', |
||||||
|
serialized_options=None, |
||||||
|
serialized_pb=_b('\n\ndemo.proto\x12\x04\x64\x65mo\"2\n\x07Request\x12\x11\n\tclient_id\x18\x01 \x01(\x03\x12\x14\n\x0crequest_data\x18\x02 \x01(\t\"4\n\x08Response\x12\x11\n\tserver_id\x18\x01 \x01(\x03\x12\x15\n\rresponse_data\x18\x02 \x01(\t2\xf0\x01\n\x08GRPCDemo\x12-\n\x0cSimpleMethod\x12\r.demo.Request\x1a\x0e.demo.Response\x12\x38\n\x15\x43lientStreamingMethod\x12\r.demo.Request\x1a\x0e.demo.Response(\x01\x12\x38\n\x15ServerStreamingMethod\x12\r.demo.Request\x1a\x0e.demo.Response0\x01\x12\x41\n\x1c\x42idirectionalStreamingMethod\x12\r.demo.Request\x1a\x0e.demo.Response(\x01\x30\x01\x62\x06proto3') |
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_REQUEST = _descriptor.Descriptor( |
||||||
|
name='Request', |
||||||
|
full_name='demo.Request', |
||||||
|
filename=None, |
||||||
|
file=DESCRIPTOR, |
||||||
|
containing_type=None, |
||||||
|
fields=[ |
||||||
|
_descriptor.FieldDescriptor( |
||||||
|
name='client_id', full_name='demo.Request.client_id', index=0, |
||||||
|
number=1, type=3, cpp_type=2, label=1, |
||||||
|
has_default_value=False, default_value=0, |
||||||
|
message_type=None, enum_type=None, containing_type=None, |
||||||
|
is_extension=False, extension_scope=None, |
||||||
|
serialized_options=None, file=DESCRIPTOR), |
||||||
|
_descriptor.FieldDescriptor( |
||||||
|
name='request_data', full_name='demo.Request.request_data', index=1, |
||||||
|
number=2, type=9, cpp_type=9, label=1, |
||||||
|
has_default_value=False, default_value=_b("").decode('utf-8'), |
||||||
|
message_type=None, enum_type=None, containing_type=None, |
||||||
|
is_extension=False, extension_scope=None, |
||||||
|
serialized_options=None, file=DESCRIPTOR), |
||||||
|
], |
||||||
|
extensions=[ |
||||||
|
], |
||||||
|
nested_types=[], |
||||||
|
enum_types=[ |
||||||
|
], |
||||||
|
serialized_options=None, |
||||||
|
is_extendable=False, |
||||||
|
syntax='proto3', |
||||||
|
extension_ranges=[], |
||||||
|
oneofs=[ |
||||||
|
], |
||||||
|
serialized_start=20, |
||||||
|
serialized_end=70, |
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
_RESPONSE = _descriptor.Descriptor( |
||||||
|
name='Response', |
||||||
|
full_name='demo.Response', |
||||||
|
filename=None, |
||||||
|
file=DESCRIPTOR, |
||||||
|
containing_type=None, |
||||||
|
fields=[ |
||||||
|
_descriptor.FieldDescriptor( |
||||||
|
name='server_id', full_name='demo.Response.server_id', index=0, |
||||||
|
number=1, type=3, cpp_type=2, label=1, |
||||||
|
has_default_value=False, default_value=0, |
||||||
|
message_type=None, enum_type=None, containing_type=None, |
||||||
|
is_extension=False, extension_scope=None, |
||||||
|
serialized_options=None, file=DESCRIPTOR), |
||||||
|
_descriptor.FieldDescriptor( |
||||||
|
name='response_data', full_name='demo.Response.response_data', index=1, |
||||||
|
number=2, type=9, cpp_type=9, label=1, |
||||||
|
has_default_value=False, default_value=_b("").decode('utf-8'), |
||||||
|
message_type=None, enum_type=None, containing_type=None, |
||||||
|
is_extension=False, extension_scope=None, |
||||||
|
serialized_options=None, file=DESCRIPTOR), |
||||||
|
], |
||||||
|
extensions=[ |
||||||
|
], |
||||||
|
nested_types=[], |
||||||
|
enum_types=[ |
||||||
|
], |
||||||
|
serialized_options=None, |
||||||
|
is_extendable=False, |
||||||
|
syntax='proto3', |
||||||
|
extension_ranges=[], |
||||||
|
oneofs=[ |
||||||
|
], |
||||||
|
serialized_start=72, |
||||||
|
serialized_end=124, |
||||||
|
) |
||||||
|
|
||||||
|
DESCRIPTOR.message_types_by_name['Request'] = _REQUEST |
||||||
|
DESCRIPTOR.message_types_by_name['Response'] = _RESPONSE |
||||||
|
_sym_db.RegisterFileDescriptor(DESCRIPTOR) |
||||||
|
|
||||||
|
Request = _reflection.GeneratedProtocolMessageType('Request', (_message.Message,), { |
||||||
|
'DESCRIPTOR' : _REQUEST, |
||||||
|
'__module__' : 'demo_pb2' |
||||||
|
# @@protoc_insertion_point(class_scope:demo.Request) |
||||||
|
}) |
||||||
|
_sym_db.RegisterMessage(Request) |
||||||
|
|
||||||
|
Response = _reflection.GeneratedProtocolMessageType('Response', (_message.Message,), { |
||||||
|
'DESCRIPTOR' : _RESPONSE, |
||||||
|
'__module__' : 'demo_pb2' |
||||||
|
# @@protoc_insertion_point(class_scope:demo.Response) |
||||||
|
}) |
||||||
|
_sym_db.RegisterMessage(Response) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_GRPCDEMO = _descriptor.ServiceDescriptor( |
||||||
|
name='GRPCDemo', |
||||||
|
full_name='demo.GRPCDemo', |
||||||
|
file=DESCRIPTOR, |
||||||
|
index=0, |
||||||
|
serialized_options=None, |
||||||
|
serialized_start=127, |
||||||
|
serialized_end=367, |
||||||
|
methods=[ |
||||||
|
_descriptor.MethodDescriptor( |
||||||
|
name='SimpleMethod', |
||||||
|
full_name='demo.GRPCDemo.SimpleMethod', |
||||||
|
index=0, |
||||||
|
containing_service=None, |
||||||
|
input_type=_REQUEST, |
||||||
|
output_type=_RESPONSE, |
||||||
|
serialized_options=None, |
||||||
|
), |
||||||
|
_descriptor.MethodDescriptor( |
||||||
|
name='ClientStreamingMethod', |
||||||
|
full_name='demo.GRPCDemo.ClientStreamingMethod', |
||||||
|
index=1, |
||||||
|
containing_service=None, |
||||||
|
input_type=_REQUEST, |
||||||
|
output_type=_RESPONSE, |
||||||
|
serialized_options=None, |
||||||
|
), |
||||||
|
_descriptor.MethodDescriptor( |
||||||
|
name='ServerStreamingMethod', |
||||||
|
full_name='demo.GRPCDemo.ServerStreamingMethod', |
||||||
|
index=2, |
||||||
|
containing_service=None, |
||||||
|
input_type=_REQUEST, |
||||||
|
output_type=_RESPONSE, |
||||||
|
serialized_options=None, |
||||||
|
), |
||||||
|
_descriptor.MethodDescriptor( |
||||||
|
name='BidirectionalStreamingMethod', |
||||||
|
full_name='demo.GRPCDemo.BidirectionalStreamingMethod', |
||||||
|
index=3, |
||||||
|
containing_service=None, |
||||||
|
input_type=_REQUEST, |
||||||
|
output_type=_RESPONSE, |
||||||
|
serialized_options=None, |
||||||
|
), |
||||||
|
]) |
||||||
|
_sym_db.RegisterServiceDescriptor(_GRPCDEMO) |
||||||
|
|
||||||
|
DESCRIPTOR.services_by_name['GRPCDemo'] = _GRPCDEMO |
||||||
|
|
||||||
|
# @@protoc_insertion_point(module_scope) |
@ -0,0 +1,106 @@ |
|||||||
|
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! |
||||||
|
import grpc |
||||||
|
|
||||||
|
import demo_pb2 as demo__pb2 |
||||||
|
|
||||||
|
|
||||||
|
class GRPCDemoStub(object): |
||||||
|
"""service是用来给GRPC服务定义方法的, 格式固定, 类似于Golang中定义一个接口 |
||||||
|
`service` is used to define methods for GRPC services in a fixed format, similar to defining an interface in Golang |
||||||
|
""" |
||||||
|
|
||||||
|
def __init__(self, channel): |
||||||
|
"""Constructor. |
||||||
|
|
||||||
|
Args: |
||||||
|
channel: A grpc.Channel. |
||||||
|
""" |
||||||
|
self.SimpleMethod = channel.unary_unary( |
||||||
|
'/demo.GRPCDemo/SimpleMethod', |
||||||
|
request_serializer=demo__pb2.Request.SerializeToString, |
||||||
|
response_deserializer=demo__pb2.Response.FromString, |
||||||
|
) |
||||||
|
self.ClientStreamingMethod = channel.stream_unary( |
||||||
|
'/demo.GRPCDemo/ClientStreamingMethod', |
||||||
|
request_serializer=demo__pb2.Request.SerializeToString, |
||||||
|
response_deserializer=demo__pb2.Response.FromString, |
||||||
|
) |
||||||
|
self.ServerStreamingMethod = channel.unary_stream( |
||||||
|
'/demo.GRPCDemo/ServerStreamingMethod', |
||||||
|
request_serializer=demo__pb2.Request.SerializeToString, |
||||||
|
response_deserializer=demo__pb2.Response.FromString, |
||||||
|
) |
||||||
|
self.BidirectionalStreamingMethod = channel.stream_stream( |
||||||
|
'/demo.GRPCDemo/BidirectionalStreamingMethod', |
||||||
|
request_serializer=demo__pb2.Request.SerializeToString, |
||||||
|
response_deserializer=demo__pb2.Response.FromString, |
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
class GRPCDemoServicer(object): |
||||||
|
"""service是用来给GRPC服务定义方法的, 格式固定, 类似于Golang中定义一个接口 |
||||||
|
`service` is used to define methods for GRPC services in a fixed format, similar to defining an interface in Golang |
||||||
|
""" |
||||||
|
|
||||||
|
def SimpleMethod(self, request, context): |
||||||
|
"""简单模式 |
||||||
|
unary-unary |
||||||
|
""" |
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED) |
||||||
|
context.set_details('Method not implemented!') |
||||||
|
raise NotImplementedError('Method not implemented!') |
||||||
|
|
||||||
|
def ClientStreamingMethod(self, request_iterator, context): |
||||||
|
"""客户端流模式(在一次调用中, 客户端可以多次向服务器传输数据, 但是服务器只能返回一次响应) |
||||||
|
stream-unary (In a single call, the client can transfer data to the server several times, |
||||||
|
but the server can only return a response once.) |
||||||
|
""" |
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED) |
||||||
|
context.set_details('Method not implemented!') |
||||||
|
raise NotImplementedError('Method not implemented!') |
||||||
|
|
||||||
|
def ServerStreamingMethod(self, request, context): |
||||||
|
"""服务端流模式(在一次调用中, 客户端只能一次向服务器传输数据, 但是服务器可以多次返回响应) |
||||||
|
unary-stream (In a single call, the client can only transmit data to the server at one time, |
||||||
|
but the server can return the response many times.) |
||||||
|
""" |
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED) |
||||||
|
context.set_details('Method not implemented!') |
||||||
|
raise NotImplementedError('Method not implemented!') |
||||||
|
|
||||||
|
def BidirectionalStreamingMethod(self, request_iterator, context): |
||||||
|
"""双向流模式 (在一次调用中, 客户端和服务器都可以向对方多次收发数据) |
||||||
|
stream-stream (In a single call, both client and server can send and receive data |
||||||
|
to each other multiple times.) |
||||||
|
""" |
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED) |
||||||
|
context.set_details('Method not implemented!') |
||||||
|
raise NotImplementedError('Method not implemented!') |
||||||
|
|
||||||
|
|
||||||
|
def add_GRPCDemoServicer_to_server(servicer, server): |
||||||
|
rpc_method_handlers = { |
||||||
|
'SimpleMethod': grpc.unary_unary_rpc_method_handler( |
||||||
|
servicer.SimpleMethod, |
||||||
|
request_deserializer=demo__pb2.Request.FromString, |
||||||
|
response_serializer=demo__pb2.Response.SerializeToString, |
||||||
|
), |
||||||
|
'ClientStreamingMethod': grpc.stream_unary_rpc_method_handler( |
||||||
|
servicer.ClientStreamingMethod, |
||||||
|
request_deserializer=demo__pb2.Request.FromString, |
||||||
|
response_serializer=demo__pb2.Response.SerializeToString, |
||||||
|
), |
||||||
|
'ServerStreamingMethod': grpc.unary_stream_rpc_method_handler( |
||||||
|
servicer.ServerStreamingMethod, |
||||||
|
request_deserializer=demo__pb2.Request.FromString, |
||||||
|
response_serializer=demo__pb2.Response.SerializeToString, |
||||||
|
), |
||||||
|
'BidirectionalStreamingMethod': grpc.stream_stream_rpc_method_handler( |
||||||
|
servicer.BidirectionalStreamingMethod, |
||||||
|
request_deserializer=demo__pb2.Request.FromString, |
||||||
|
response_serializer=demo__pb2.Response.SerializeToString, |
||||||
|
), |
||||||
|
} |
||||||
|
generic_handler = grpc.method_handlers_generic_handler( |
||||||
|
'demo.GRPCDemo', rpc_method_handlers) |
||||||
|
server.add_generic_rpc_handlers((generic_handler,)) |
@ -0,0 +1,114 @@ |
|||||||
|
# Copyright 2019 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
"""The example of four ways of data transmission using gRPC in Python.""" |
||||||
|
|
||||||
|
from threading import Thread |
||||||
|
from concurrent import futures |
||||||
|
|
||||||
|
import grpc |
||||||
|
import demo_pb2_grpc |
||||||
|
import demo_pb2 |
||||||
|
|
||||||
|
SERVER_ADDRESS = 'localhost:23333' |
||||||
|
SERVER_ID = 1 |
||||||
|
|
||||||
|
|
||||||
|
class DemoServer(demo_pb2_grpc.GRPCDemoServicer): |
||||||
|
|
||||||
|
# 一元模式(在一次调用中, 客户端只能向服务器传输一次请求数据, 服务器也只能返回一次响应) |
||||||
|
# unary-unary(In a single call, the client can only send request once, and the server can |
||||||
|
# only respond once.) |
||||||
|
def SimpleMethod(self, request, context): |
||||||
|
print("SimpleMethod called by client(%d) the message: %s" % |
||||||
|
(request.client_id, request.request_data)) |
||||||
|
response = demo_pb2.Response( |
||||||
|
server_id=SERVER_ID, |
||||||
|
response_data="Python server SimpleMethod Ok!!!!") |
||||||
|
return response |
||||||
|
|
||||||
|
# 客户端流模式(在一次调用中, 客户端可以多次向服务器传输数据, 但是服务器只能返回一次响应) |
||||||
|
# stream-unary (In a single call, the client can transfer data to the server several times, |
||||||
|
# but the server can only return a response once.) |
||||||
|
def ClientStreamingMethod(self, request_iterator, context): |
||||||
|
print("ClientStreamingMethod called by client...") |
||||||
|
for request in request_iterator: |
||||||
|
print("recv from client(%d), message= %s" % (request.client_id, |
||||||
|
request.request_data)) |
||||||
|
response = demo_pb2.Response( |
||||||
|
server_id=SERVER_ID, |
||||||
|
response_data="Python server ClientStreamingMethod ok") |
||||||
|
return response |
||||||
|
|
||||||
|
# 服务端流模式(在一次调用中, 客户端只能一次向服务器传输数据, 但是服务器可以多次返回响应) |
||||||
|
# unary-stream (In a single call, the client can only transmit data to the server at one time, |
||||||
|
# but the server can return the response many times.) |
||||||
|
def ServerStreamingMethod(self, request, context): |
||||||
|
print("ServerStreamingMethod called by client(%d), message= %s" % |
||||||
|
(request.client_id, request.request_data)) |
||||||
|
|
||||||
|
# 创建一个生成器 |
||||||
|
# create a generator |
||||||
|
def response_messages(): |
||||||
|
for i in range(5): |
||||||
|
response = demo_pb2.Response( |
||||||
|
server_id=SERVER_ID, |
||||||
|
response_data=("send by Python server, message=%d" % i)) |
||||||
|
yield response |
||||||
|
|
||||||
|
return response_messages() |
||||||
|
|
||||||
|
# 双向流模式 (在一次调用中, 客户端和服务器都可以向对方多次收发数据) |
||||||
|
# stream-stream (In a single call, both client and server can send and receive data |
||||||
|
# to each other multiple times.) |
||||||
|
def BidirectionalStreamingMethod(self, request_iterator, context): |
||||||
|
print("BidirectionalStreamingMethod called by client...") |
||||||
|
|
||||||
|
# 开启一个子线程去接收数据 |
||||||
|
# Open a sub thread to receive data |
||||||
|
def parse_request(): |
||||||
|
for request in request_iterator: |
||||||
|
print("recv from client(%d), message= %s" % |
||||||
|
(request.client_id, request.request_data)) |
||||||
|
|
||||||
|
t = Thread(target=parse_request) |
||||||
|
t.start() |
||||||
|
|
||||||
|
for i in range(5): |
||||||
|
yield demo_pb2.Response( |
||||||
|
server_id=SERVER_ID, |
||||||
|
response_data=("send by Python server, message= %d" % i)) |
||||||
|
|
||||||
|
t.join() |
||||||
|
|
||||||
|
|
||||||
|
def main(): |
||||||
|
server = grpc.server(futures.ThreadPoolExecutor()) |
||||||
|
|
||||||
|
demo_pb2_grpc.add_GRPCDemoServicer_to_server(DemoServer(), server) |
||||||
|
|
||||||
|
server.add_insecure_port(SERVER_ADDRESS) |
||||||
|
print("------------------start Python GRPC server") |
||||||
|
server.start() |
||||||
|
server.wait_for_termination() |
||||||
|
|
||||||
|
# If raise Error: |
||||||
|
# AttributeError: '_Server' object has no attribute 'wait_for_termination' |
||||||
|
# You can use the following code instead: |
||||||
|
# import time |
||||||
|
# while 1: |
||||||
|
# time.sleep(10) |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
main() |
Loading…
Reference in new issue