aboutsummaryrefslogtreecommitdiffhomepage
path: root/examples/cpp/helloworld/greeter_async_server.cc
diff options
context:
space:
mode:
authorGravatar Craig Tiller <ctiller@google.com>2015-09-03 09:37:02 -0700
committerGravatar Craig Tiller <ctiller@google.com>2015-09-03 09:37:02 -0700
commitd6599a39e48b152eeb1b55d427fbe5f22817b663 (patch)
treefdf2f1466f394008aebd93ee6e5dc18d6d9049c0 /examples/cpp/helloworld/greeter_async_server.cc
parentaca3211b0f41aa862a424327de6d3a36e455a3c4 (diff)
Replicate C++ docs from master to beta branch
Original PR #3074 by @dgquintas
Diffstat (limited to 'examples/cpp/helloworld/greeter_async_server.cc')
-rw-r--r--examples/cpp/helloworld/greeter_async_server.cc60
1 files changed, 51 insertions, 9 deletions
diff --git a/examples/cpp/helloworld/greeter_async_server.cc b/examples/cpp/helloworld/greeter_async_server.cc
index 189c3afe6d..b2047a8ce5 100644
--- a/examples/cpp/helloworld/greeter_async_server.cc
+++ b/examples/cpp/helloworld/greeter_async_server.cc
@@ -36,13 +36,8 @@
#include <string>
#include <thread>
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
-#include <grpc++/completion_queue.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
+#include <grpc++/grpc++.h>
+
#include "helloworld.grpc.pb.h"
using grpc::Server;
@@ -59,6 +54,7 @@ class ServerImpl final {
public:
~ServerImpl() {
server_->Shutdown();
+ // Always shutdown the completion queue after the server.
cq_->Shutdown();
}
@@ -67,56 +63,102 @@ class ServerImpl final {
std::string server_address("0.0.0.0:50051");
ServerBuilder builder;
+ // Listen on the given address without any authentication mechanism.
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+ // Register "service_" as the instance through which we'll communicate with
+ // clients. In this case it corresponds to an *asynchronous* service.
builder.RegisterAsyncService(&service_);
+ // Get hold of the completion queue used for the asynchronous communication
+ // with the gRPC runtime.
cq_ = builder.AddCompletionQueue();
+ // Finally assemble the server.
server_ = builder.BuildAndStart();
std::cout << "Server listening on " << server_address << std::endl;
+ // Proceed to the server's main loop.
HandleRpcs();
}
private:
+ // Class encompasing the state and logic needed to serve a request.
class CallData {
public:
+ // Take in the "service" instance (in this case representing an asynchronous
+ // server) and the completion queue "cq" used for asynchronous communication
+ // with the gRPC runtime.
CallData(Greeter::AsyncService* service, ServerCompletionQueue* cq)
: service_(service), cq_(cq), responder_(&ctx_), status_(CREATE) {
+ // Invoke the serving logic right away.
Proceed();
}
void Proceed() {
if (status_ == CREATE) {
+ // As part of the initial CREATE state, we *request* that the system
+ // start processing SayHello requests. In this request, "this" acts are
+ // the tag uniquely identifying the request (so that different CallData
+ // instances can serve different requests concurrently), in this case
+ // the memory address of this CallData instance.
service_->RequestSayHello(&ctx_, &request_, &responder_, cq_, cq_,
this);
+ // Make this instance progress to the PROCESS state.
status_ = PROCESS;
} else if (status_ == PROCESS) {
+ // Spawn a new CallData instance to serve new clients while we process
+ // the one for this CallData. The instance will deallocate itself as
+ // part of its FINISH state.
new CallData(service_, cq_);
+
+ // The actual processing.
std::string prefix("Hello ");
reply_.set_message(prefix + request_.name());
+
+ // And we are done! Let the gRPC runtime know we've finished, using the
+ // memory address of this instance as the uniquely identifying tag for
+ // the event.
responder_.Finish(reply_, Status::OK, this);
status_ = FINISH;
} else {
+ GPR_ASSERT(status_ == FINISH);
+ // Once in the FINISH state, deallocate ourselves (CallData).
delete this;
}
}
private:
+ // The means of communication with the gRPC runtime for an asynchronous
+ // server.
Greeter::AsyncService* service_;
+ // The producer-consumer queue where for asynchronous server notifications.
ServerCompletionQueue* cq_;
+ // Context for the rpc, allowing to tweak aspects of it such as the use
+ // of compression, authentication, as well as to send metadata back to the
+ // client.
ServerContext ctx_;
+
+ // What we get from the client.
HelloRequest request_;
+ // What we send back to the client.
HelloReply reply_;
+
+ // The means to get back to the client.
ServerAsyncResponseWriter<HelloReply> responder_;
+
+ // Let's implement a tiny state machine with the following states.
enum CallStatus { CREATE, PROCESS, FINISH };
- CallStatus status_;
+ CallStatus status_; // The current serving state.
};
// This can be run in multiple threads if needed.
void HandleRpcs() {
+ // Spawn a new CallData instance to serve new clients.
new CallData(&service_, cq_.get());
- void* tag;
+ void* tag; // uniquely identifies a request.
bool ok;
while (true) {
+ // Block waiting to read the next event from the completion queue. The
+ // event is uniquely identified by its tag, which in this case is the
+ // memory address of a CallData instance.
cq_->Next(&tag, &ok);
GPR_ASSERT(ok);
static_cast<CallData*>(tag)->Proceed();