- Quick start
- Quick start
- Prerequisites
- gRPC
- gRPC tools
- Download the example
- Run a gRPC application
- Update the gRPC service
- Generate gRPC code
- Update and run the application
- Update the server
- Update the client
- Run!
- What’s next
- How to implement bi-directional streaming using gRPC with Python (Server) – Part 1
- gRPC Streaming Server:
- gRPC Streaming Client:
- Saved searches
- Use saved searches to filter your results more quickly
- melledijkstra/python-grpc-chat
- Name already in use
- Sign In Required
- Launching GitHub Desktop
- Launching GitHub Desktop
- Launching Xcode
- Launching Visual Studio Code
- Latest commit
- Git stats
- Files
- README.md
- About
Quick start
This guide gets you started with gRPC in Python with a simple working example.
Quick start
Prerequisites
If necessary, upgrade your version of pip :
$ python -m pip install --upgrade pip
If you cannot upgrade pip due to a system-owned installation, you can run the example in a virtualenv:
$ python -m pip install virtualenv $ virtualenv venv $ source venv/bin/activate $ python -m pip install --upgrade pip
gRPC
$ python -m pip install grpcio
Or, to install it system wide:
$ sudo python -m pip install grpcio
gRPC tools
Python’s gRPC tools include the protocol buffer compiler protoc and the special plugin for generating server and client code from .proto service definitions. For the first part of our quick-start example, we’ve already generated the server and client stubs from helloworld.proto , but you’ll need the tools for the rest of our quick start, as well as later tutorials and your own projects.
To install gRPC tools, run:
$ python -m pip install grpcio-tools
Download the example
You’ll need a local copy of the example code to work through this quick start. Download the example code from our GitHub repository (the following command clones the entire repository, but you just need the examples for this quick start and other tutorials):
# Clone the repository to get the example code: $ git clone -b v1.56.0 --depth 1 --shallow-submodules https://github.com/grpc/grpc # Navigate to the "hello, world" Python example: $ cd grpc/examples/python/helloworld
Run a gRPC application
From the examples/python/helloworld directory:
Congratulations! You’ve just run a client-server application with gRPC.
Update the gRPC service
Now let’s look at how to update the application with an extra method on the server for the client to call. Our gRPC service is defined using protocol buffers; you can find out lots more about how to define a service in a .proto file in Introduction to gRPC and Basics tutorial. For now all you need to know is that both the server and the client “stub” have a SayHello RPC method that takes a HelloRequest parameter from the client and returns a HelloReply from the server, and that this method is defined like this:
// 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; >
Let’s update this so that the Greeter service has two methods. Edit examples/protos/helloworld.proto and update it with a new SayHelloAgain method, with the same request and response types:
// The greeting service definition. service Greeter // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) <> // Sends another greeting rpc SayHelloAgain (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; >
Remember to save the file!
Generate gRPC code
Next we need to update the gRPC code used by our application to use the new service definition.
From the examples/python/helloworld directory, run:
$ python -m grpc_tools.protoc -I../../protos --python_out=. --pyi_out=. --grpc_python_out=. ../../protos/helloworld.proto
This regenerates helloworld_pb2.py which contains our generated request and response classes and helloworld_pb2_grpc.py which contains our generated client and server classes.
Update and run the application
We now have new generated server and client code, but we still need to implement and call the new method in the human-written parts of our example application.
Update the server
In the same directory, open greeter_server.py . Implement the new method like this:
class Greeter(helloworld_pb2_grpc.GreeterServicer): def SayHello(self, request, context): return helloworld_pb2.HelloReply(message=f'Hello, request.name>!') def SayHelloAgain(self, request, context): return helloworld_pb2.HelloReply(message=f'Hello again, request.name>!') .
Update the client
In the same directory, open greeter_client.py . Call the new method like this:
def run(): with grpc.insecure_channel('localhost:50051') as channel: stub = helloworld_pb2_grpc.GreeterStub(channel) response = stub.SayHello(helloworld_pb2.HelloRequest(name='you')) print("Greeter client received: " + response.message) response = stub.SayHelloAgain(helloworld_pb2.HelloRequest(name='you')) print("Greeter client received: " + response.message)
Run!
Just like we did before, from the examples/python/helloworld directory:
What’s next
How to implement bi-directional streaming using gRPC with Python (Server) – Part 1
In our previous tutorials, we have demonstrated how to implement bi-directional streaming using NodeJS. Since gRPC is just a protocol definition so it can be implemented in any possible language. So today we will demonstrate how to setup a bi-directional server using python & gRPC.
The codebase has been shared on GitHub for your convenience as follows: https://github.com/techunits/bidirectional-streaming-grpc-sample-python
In order to execute the gRPC streaming, we will need the following pip libraries as pre-requisites:
grpcio==1.39.0 grpcio-tools==1.39.0 protobuf==3.17.3 six==1.16.0 uuid==1.30
The very first step to setup any gRPC communication is to create a data contract in the form of a protocol buffer file. In our demonstration, we will use a simple contract that should be able to create some resource entries to the server in the stream and expect a response in the form of a stream.
Our proto file as follows:
syntax = "proto3"; package SamplePackage; message EntryCreateRequest < string title = 1; string code = 2; string description = 3; >message EntryResponse < string string title = 2; string code = 3; string description = 4; int32 created_on = 6; >service SampleService < rpc createBulkEntries(stream EntryCreateRequest) returns (stream EntryResponse) <>>
Unlike NodeJS, python classes will not able to read the proto files directly, so we have to convert the proto into native python classes. The following command will generate 2 python class files sample_pb2_grpc.py & sample_pb2.py.
python -m grpc_tools.protoc -I./proto --python_out=./proto/ --grpc_python_out=./proto/ ./proto/sample.proto
gRPC Streaming Server:
Now we will define our server process which will read the above classes and servicer as follows:
# import required libraries & proto defn. import grpc from concurrent import futures from proto import sample_pb2_grpc # import servicer from servicers import SampleServiceServicer def serve(): # initialize server with 4 workers server = grpc.server(futures.ThreadPoolExecutor(max_workers=4)) # attach servicer method to the server sample_pb2_grpc.add_SampleServiceServicer_to_server(SampleServiceServicer(), server) # start the server on the port 50051 server.add_insecure_port("0.0.0.0:50051") server.start() print("Started gRPC server: 0.0.0.0:50051") # server loop to keep the process running server.wait_for_termination() # invoke the server method if __name__ == "__main__": serve()
The server process is having a dependency on the servicer method SampleServiceServicer defined as follows:
# import required libraries & proto defn. from proto import sample_pb2_grpc, sample_pb2 import uuid from datetime import datetime class SampleServiceServicer(sample_pb2_grpc.SampleServiceServicer): ''' this servicer method will read the request from the iterator supplied by incoming stream and send back the response in a stream ''' def createBulkEntries(self, request_iterator, context): entry_info = dict() for request in request_iterator: print(request) ##### save to database ##### # simulate the response after saving to database entry_info = < "id": str(uuid.uuid4()), "title": request.title, "code": request.code, "description": request.description, "created_on": round(datetime.now().timestamp()) ># stream the response back yield sample_pb2.EntryResponse(**entry_info)
Once we are done with the above steps, we should be able to start the server with the following command:
$ python serve.py Started gRPC server: 0.0.0.0:50051
While building the server script we have using sConnector to test and debug our script visually even before creating any client. This helps a lot for a faster development cycle. Screenshot as follows:
gRPC Streaming Client:
In our next tutorial, we will explain how to implement a client to connect to the streaming server and send/receive the data as follows:
Saved searches
Use saved searches to filter your results more quickly
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
Chat application created with gRPC. This was a study for bidirectional gRPC streaming.
melledijkstra/python-grpc-chat
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Sign In Required
Please sign in to use Codespaces.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
Chat application created with gRPC. This was a study for bidirectional gRPC streaming.
class ChatServer(rpc.ChatServerServicer): def __init__(self): # List with all the chat history self.chats = [] # The stream which will be used to send new messages to clients def ChatStream(self, request_iterator, context): """ This is a response-stream type call. This means the server can keep sending messages Every client opens this connection and waits for server to send new messages :param request_iterator: :param context: :return: """ lastindex = 0 # For every client a infinite loop starts (in gRPC's own managed thread) while True: # Check if there are any new messages while len(self.chats) > lastindex: n = self.chats[lastindex] lastindex += 1 yield n def SendNote(self, request: chat.Note, context): """ This method is called when a clients sends a Note to the server. :param request: :param context: :return: """ print("[<>] <>".format(request.name, request.message)) # Add it to the chat history self.chats.append(request) return chat.Empty()
address = 'localhost' port = 11912 class Client: def __init__(self, u: str, window): # the frame to put ui components on self.window = window self.username = u # create a gRPC channel + stub channel = grpc.insecure_channel(address + ':' + str(port)) self.conn = rpc.ChatServerStub(channel) # create new listening thread for when new message streams come in threading.Thread(target=self.__listen_for_messages, daemon=True).start() self.__setup_ui() self.window.mainloop() def __listen_for_messages(self): """ This method will be ran in a separate thread as the main/ui thread, because the for-in call is blocking when waiting for new messages """ for note in self.conn.ChatStream(chat.Empty()): print("R[<>] <>".format(note.name, note.message)) self.chat_list.insert(END, "[<>] <>\n".format(note.name, note.message)) def send_message(self, event): """ This method is called when user enters something into the textbox """ message = self.entry_message.get() if message is not '': n = chat.Note() n.name = self.username n.message = message print("S[<>] <>".format(n.name, n.message)) self.conn.SendNote(n) .
syntax = "proto3"; package grpc; message Empty <> // I called it Note because message Message is annoying to work with message Note < string name = 1; string message = 2; > service ChatServer < // This bi-directional stream makes it possible to send and receive Notes between 2 persons rpc ChatStream (Empty) returns (stream Note); rpc SendNote (Note) returns (Empty); >
About
Chat application created with gRPC. This was a study for bidirectional gRPC streaming.