mirror of https://github.com/grpc/grpc.git
commit
39bd784e36
5 changed files with 366 additions and 0 deletions
@ -0,0 +1,96 @@ |
|||||||
|
#
|
||||||
|
# Copyright 2018 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.
|
||||||
|
#
|
||||||
|
HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
|
||||||
|
SYSTEM ?= $(HOST_SYSTEM)
|
||||||
|
CXX = g++
|
||||||
|
CPPFLAGS += `pkg-config --cflags protobuf grpc`
|
||||||
|
CXXFLAGS += -std=c++11
|
||||||
|
ifeq ($(SYSTEM),Darwin) |
||||||
|
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||||
|
-lgrpc++_reflection\
|
||||||
|
-ldl
|
||||||
|
else |
||||||
|
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||||
|
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
|
||||||
|
-ldl
|
||||||
|
endif |
||||||
|
PROTOC = protoc
|
||||||
|
GRPC_CPP_PLUGIN = grpc_cpp_plugin
|
||||||
|
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
|
||||||
|
PROTOS_PATH = ../../protos
|
||||||
|
vpath %.proto $(PROTOS_PATH)
|
||||||
|
all: system-check greeter_client greeter_server
|
||||||
|
greeter_client: helloworld.pb.o helloworld.grpc.pb.o greeter_client.o
|
||||||
|
$(CXX) $^ $(LDFLAGS) -o $@
|
||||||
|
greeter_server: helloworld.pb.o helloworld.grpc.pb.o greeter_server.o
|
||||||
|
$(CXX) $^ $(LDFLAGS) -o $@
|
||||||
|
.PRECIOUS: %.grpc.pb.cc
|
||||||
|
%.grpc.pb.cc: %.proto |
||||||
|
$(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<
|
||||||
|
.PRECIOUS: %.pb.cc
|
||||||
|
%.pb.cc: %.proto |
||||||
|
$(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $<
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server
|
||||||
|
# The following is to test your system and ensure a smoother experience.
|
||||||
|
# They are by no means necessary to actually compile a grpc-enabled software.
|
||||||
|
PROTOC_CMD = which $(PROTOC)
|
||||||
|
PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3
|
||||||
|
PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN)
|
||||||
|
HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false)
|
||||||
|
ifeq ($(HAS_PROTOC),true) |
||||||
|
HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
|
||||||
|
endif |
||||||
|
HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false)
|
||||||
|
SYSTEM_OK = false
|
||||||
|
ifeq ($(HAS_VALID_PROTOC),true) |
||||||
|
ifeq ($(HAS_PLUGIN),true) |
||||||
|
SYSTEM_OK = true
|
||||||
|
endif |
||||||
|
endif |
||||||
|
system-check:
|
||||||
|
ifneq ($(HAS_VALID_PROTOC),true) |
||||||
|
@echo " DEPENDENCY ERROR"
|
||||||
|
@echo
|
||||||
|
@echo "You don't have protoc 3.0.0 installed in your path."
|
||||||
|
@echo "Please install Google protocol buffers 3.0.0 and its compiler."
|
||||||
|
@echo "You can find it here:"
|
||||||
|
@echo
|
||||||
|
@echo " https://github.com/google/protobuf/releases/tag/v3.0.0"
|
||||||
|
@echo
|
||||||
|
@echo "Here is what I get when trying to evaluate your version of protoc:"
|
||||||
|
@echo
|
||||||
|
-$(PROTOC) --version
|
||||||
|
@echo
|
||||||
|
@echo
|
||||||
|
endif |
||||||
|
ifneq ($(HAS_PLUGIN),true) |
||||||
|
@echo " DEPENDENCY ERROR"
|
||||||
|
@echo
|
||||||
|
@echo "You don't have the grpc c++ protobuf plugin installed in your path."
|
||||||
|
@echo "Please install grpc. You can find it here:"
|
||||||
|
@echo
|
||||||
|
@echo " https://github.com/grpc/grpc"
|
||||||
|
@echo
|
||||||
|
@echo "Here is what I get when trying to detect if you have the plugin:"
|
||||||
|
@echo
|
||||||
|
-which $(GRPC_CPP_PLUGIN)
|
||||||
|
@echo
|
||||||
|
@echo
|
||||||
|
endif |
||||||
|
ifneq ($(SYSTEM_OK),true) |
||||||
|
@false
|
||||||
|
endif |
@ -0,0 +1,66 @@ |
|||||||
|
# Metadata Example |
||||||
|
|
||||||
|
## Overview |
||||||
|
|
||||||
|
This example shows you how to add custom headers on the client and server and |
||||||
|
how to access them. |
||||||
|
|
||||||
|
Custom metadata must follow the "Custom-Metadata" format listed in |
||||||
|
https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md, with the |
||||||
|
exception of binary headers, which don't have to be base64 encoded. |
||||||
|
|
||||||
|
### Get the tutorial source code |
||||||
|
The example code for this and our other examples lives in the `examples` directory. Clone this repository to your local machine by running the following command: |
||||||
|
```sh |
||||||
|
$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc |
||||||
|
``` |
||||||
|
Change your current directory to examples/cpp/metadata |
||||||
|
```sh |
||||||
|
$ cd examples/cpp/metadata |
||||||
|
``` |
||||||
|
|
||||||
|
### Generating gRPC code |
||||||
|
To generate the client and server side interfaces: |
||||||
|
```sh |
||||||
|
$ make helloworld.grpc.pb.cc helloworld.pb.cc |
||||||
|
``` |
||||||
|
Which internally invokes the proto-compiler as: |
||||||
|
```sh |
||||||
|
$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto |
||||||
|
$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto |
||||||
|
``` |
||||||
|
### Try it! |
||||||
|
Build client and server: |
||||||
|
|
||||||
|
```sh |
||||||
|
$ make |
||||||
|
``` |
||||||
|
|
||||||
|
Run the server, which will listen on port 50051: |
||||||
|
|
||||||
|
```sh |
||||||
|
$ ./greeter_server |
||||||
|
``` |
||||||
|
|
||||||
|
Run the client (in a different terminal): |
||||||
|
|
||||||
|
```sh |
||||||
|
$ ./greeter_client |
||||||
|
``` |
||||||
|
|
||||||
|
If things go smoothly, you will see in the client terminal: |
||||||
|
|
||||||
|
"Client received initial metadata from server: initial metadata value" |
||||||
|
"Client received trailing metadata from server: trailing metadata value" |
||||||
|
"Client received message: Hello World" |
||||||
|
|
||||||
|
|
||||||
|
And in the server terminal: |
||||||
|
|
||||||
|
"Header key: custom-bin , value: 01234567" |
||||||
|
"Header key: custom-header , value: Custom Value" |
||||||
|
"Header key: user-agent , value: grpc-c++/1.16.0-dev grpc-c/6.0.0-dev (linux; chttp2; gao)" |
||||||
|
|
||||||
|
We did not add the user-agent metadata as a custom header. This shows how |
||||||
|
the gRPC framework adds some headers under the hood that may show up in the |
||||||
|
metadata map. |
@ -0,0 +1,95 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2015 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <iostream> |
||||||
|
#include <memory> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <grpcpp/grpcpp.h> |
||||||
|
|
||||||
|
#ifdef BAZEL_BUILD |
||||||
|
#include "examples/protos/helloworld.grpc.pb.h" |
||||||
|
#else |
||||||
|
#include "helloworld.grpc.pb.h" |
||||||
|
#endif |
||||||
|
|
||||||
|
using grpc::Channel; |
||||||
|
using grpc::ClientContext; |
||||||
|
using grpc::Status; |
||||||
|
using helloworld::HelloRequest; |
||||||
|
using helloworld::HelloReply; |
||||||
|
using helloworld::Greeter; |
||||||
|
|
||||||
|
class CustomHeaderClient { |
||||||
|
public: |
||||||
|
CustomHeaderClient(std::shared_ptr<Channel> channel) |
||||||
|
: stub_(Greeter::NewStub(channel)) {} |
||||||
|
|
||||||
|
// Assembles the client's payload, sends it and presents the response back
|
||||||
|
// from the server.
|
||||||
|
std::string SayHello(const std::string& user) { |
||||||
|
// Data we are sending to the server.
|
||||||
|
HelloRequest request; |
||||||
|
request.set_name(user); |
||||||
|
|
||||||
|
// Container for the data we expect from the server.
|
||||||
|
HelloReply reply; |
||||||
|
|
||||||
|
// Context for the client. It could be used to convey extra information to
|
||||||
|
// the server and/or tweak certain RPC behaviors.
|
||||||
|
ClientContext context; |
||||||
|
|
||||||
|
// Setting custom metadata to be sent to the server
|
||||||
|
context.AddMetadata("custom-header", "Custom Value"); |
||||||
|
|
||||||
|
// Setting custom binary metadata
|
||||||
|
char bytes[8] = {'\0', '\1', '\2', '\3', |
||||||
|
'\4', '\5', '\6', '\7'}; |
||||||
|
context.AddMetadata("custom-bin", grpc::string(bytes, 8)); |
||||||
|
|
||||||
|
// The actual RPC.
|
||||||
|
Status status = stub_->SayHello(&context, request, &reply); |
||||||
|
|
||||||
|
// Act upon its status.
|
||||||
|
if (status.ok()) { |
||||||
|
std::cout << "Client received initial metadata from server: " << context.GetServerInitialMetadata().find("custom-server-metadata")->second << std::endl; |
||||||
|
std::cout << "Client received trailing metadata from server: " << context.GetServerTrailingMetadata().find("custom-trailing-metadata")->second << std::endl; |
||||||
|
return reply.message(); |
||||||
|
} else { |
||||||
|
std::cout << status.error_code() << ": " << status.error_message() |
||||||
|
<< std::endl; |
||||||
|
return "RPC failed"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
std::unique_ptr<Greeter::Stub> stub_; |
||||||
|
}; |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||||
|
// are created. This channel models a connection to an endpoint (in this case,
|
||||||
|
// localhost at port 50051). We indicate that the channel isn't authenticated
|
||||||
|
// (use of InsecureChannelCredentials()).
|
||||||
|
CustomHeaderClient greeter(grpc::CreateChannel( |
||||||
|
"localhost:50051", grpc::InsecureChannelCredentials())); |
||||||
|
std::string user("world"); |
||||||
|
std::string reply = greeter.SayHello(user); |
||||||
|
std::cout << "Client received message: " << reply << std::endl; |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,94 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2015 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <iostream> |
||||||
|
#include <memory> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <grpcpp/grpcpp.h> |
||||||
|
|
||||||
|
#ifdef BAZEL_BUILD |
||||||
|
#include "examples/protos/helloworld.grpc.pb.h" |
||||||
|
#else |
||||||
|
#include "helloworld.grpc.pb.h" |
||||||
|
#endif |
||||||
|
|
||||||
|
using grpc::Server; |
||||||
|
using grpc::ServerBuilder; |
||||||
|
using grpc::ServerContext; |
||||||
|
using grpc::Status; |
||||||
|
using helloworld::HelloRequest; |
||||||
|
using helloworld::HelloReply; |
||||||
|
using helloworld::Greeter; |
||||||
|
|
||||||
|
// Logic and data behind the server's behavior.
|
||||||
|
class GreeterServiceImpl final : public Greeter::Service { |
||||||
|
Status SayHello(ServerContext* context, const HelloRequest* request, |
||||||
|
HelloReply* reply) override { |
||||||
|
std::string prefix("Hello "); |
||||||
|
|
||||||
|
// Get the client's initial metadata
|
||||||
|
std::cout << "Client metadata: " << std::endl; |
||||||
|
const std::multimap<grpc::string_ref, grpc::string_ref> metadata = context->client_metadata(); |
||||||
|
for (auto iter = metadata.begin(); iter != metadata.end(); ++iter) { |
||||||
|
std::cout << "Header key: " << iter->first << ", value: "; |
||||||
|
// Check for binary value
|
||||||
|
size_t isbin = iter->first.find("-bin"); |
||||||
|
if ((isbin != std::string::npos) && (isbin + 4 == iter->first.size())) { |
||||||
|
std::cout << std::hex; |
||||||
|
for (auto c : iter->second) { |
||||||
|
std::cout << static_cast<unsigned int>(c); |
||||||
|
} |
||||||
|
std::cout << std::dec; |
||||||
|
} else { |
||||||
|
std::cout << iter->second; |
||||||
|
} |
||||||
|
std::cout << std::endl; |
||||||
|
} |
||||||
|
|
||||||
|
context->AddInitialMetadata("custom-server-metadata", "initial metadata value"); |
||||||
|
context->AddTrailingMetadata("custom-trailing-metadata", "trailing metadata value"); |
||||||
|
reply->set_message(prefix + request->name()); |
||||||
|
return Status::OK; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
void RunServer() { |
||||||
|
std::string server_address("0.0.0.0:50051"); |
||||||
|
GreeterServiceImpl service; |
||||||
|
|
||||||
|
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 *synchronous* service.
|
||||||
|
builder.RegisterService(&service); |
||||||
|
// Finally assemble the server.
|
||||||
|
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||||
|
std::cout << "Server listening on " << server_address << std::endl; |
||||||
|
|
||||||
|
// Wait for the server to shutdown. Note that some other thread must be
|
||||||
|
// responsible for shutting down the server for this call to ever return.
|
||||||
|
server->Wait(); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
RunServer(); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
Loading…
Reference in new issue