Grpc: Grpc C++ client and Grpc java server, asynchronous bidirectional stream - c++

I am trying to write a cpp client for a bi-directional stream api.
With the following client code, I am able to instantiate a Stream observer on the server. However the problem is with the invocation of the onNext function on the Server StreamObserver.
Is there a certain protocol to make this call using a cpp client and java server ?
Proto file:
// A client-to-server stream RPC to append data
rpc append(stream ratis.common.RaftClientRequestProto)
returns (stream ratis.common.RaftClientReplyProto) {}
Server code
#Override
public void onNext(RaftClientRequestProto request) {
try {
final RaftClientRequest r = ClientProtoUtils.toRaftClientRequest(request);
LOG.info("recieved request " + r.getCallId());
final PendingAppend p = new PendingAppend(r);
slidingWindow.receivedRequest(p, this::processClientRequestAsync);
} catch (Throwable e) {
responseError(e, () -> "onNext for " + ClientProtoUtils.toString(request));
}
}
Client code
RaftClientRequestProto req = create_request(read_requet, sizeof(ContainerCommandRequestProto));
grpc::ClientContext ctx;
std::shared_ptr<ClientReaderWriter<RaftClientRequestProto, RaftClientReplyProto>> cli_stream(stub->append(&ctx));
std::thread writer([cli_stream]() {
RaftClientReplyProto resp;
std::cout << "goind to read " << std::endl;
cli_stream->Read(&resp);
std::cout << "read done" << std::endl;
});
std::cout << "Thread started" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
std::cout << "Doing writes" << std::endl;
cli_stream->Write(req);
cli_stream->WritesDone();
std::cout << "writes done" << std::endl;

This issue was because of difference in protobuf version.

Related

Send request from a server to a connected client with RSocket C++

could someone kindly help me with the RSocket issue? I'm trying to send a request from the Server to a connected Client, but the Client Responder does not fire callbacks. I'm using the RSocket-cpp library.
Server code:
TcpConnectionAcceptor::Options opts;
opts.address = folly::SocketAddress("::", FLAGS_port);
opts.threads = 2;
// RSocket server accepting on TCP
auto rs = std::make_unique<TcpConnectionAcceptor>(std::move(opts));
auto serverThread = std::thread([&rs] {
// start accepting connections
rs->start(
[](std::unique_ptr<DuplexConnection> connection, folly::EventBase& eventBase) {
LOG(INFO) << "new incoming connected" << std::endl;
auto client = RSocket::createClientFromConnection(
std::move(connection), *eventBase.getEventBase(), SetupParameters(), nullptr, std::make_shared<GenericRequestResponseResponder>());
LOG(INFO) << "send data" << std::endl;
client->getRequester()->requestResponse(Payload("hello2"))->subscribe([](Payload p) {
LOG(INFO) << "Received1 >> " << p.moveDataToString() << std::endl;
});
LOG(INFO) << "request is sent from server" << std::endl;
});
});
Output:
I0327 07:11:33.583813 23622 RequestResponseHelloWorld_Server.cpp:95] new incoming connected
I0327 07:11:33.602982 23622 RequestResponseHelloWorld_Server.cpp:100] send data
I0327 07:11:33.604566 23622 RequestResponseHelloWorld_Server.cpp:105] request is sent from server
Client code:
class GenericRequestResponseResponder : public rsocket::RSocketResponder
{
public:
std::shared_ptr<Single<Payload>> handleRequestResponse(
Payload request,
StreamId /*streamId*/) override
{
LOG(INFO) << "GenericRequestResponseResponder.handleRequestResponse "
<< request << std::endl;
// string from payload data
auto requestString = request.moveDataToString();
return Single<Payload>::create(
[name = std::move(requestString)](auto subscriber) {
std::stringstream ss;
ss << "Ack " << name << "!";
std::string s = ss.str();
subscriber->onSubscribe(SingleSubscriptions::empty());
subscriber->onSuccess(Payload(s, "metadata"));
});
}
void handleFireAndForget(
rsocket::Payload request,
rsocket::StreamId /*streamId*/) override
{
LOG(INFO) << "GenericRequestResponseResponder.handleRequestResponse "
<< request << std::endl;
}
};
folly::SocketAddress address{folly::SocketAddress(host, port)};
std::shared_ptr<TelemetryConnection> connection{nullptr};
RSocket::createConnectedClient(
std::make_unique<TcpConnectionFactory>(
*m_worker->getEventBase(), std::move(address)), SetupParameters(), std::make_shared<GenericRequestResponseResponder>())
.thenValue([this, host, port, &connection](auto&& client) {
LOG(INFO) << "client is created" << std::endl;
m_clientList.append(client);
})
.thenError(
folly::tag_t<std::exception>{},
[&](const std::exception&) {
LOG(ERROR) << "connection failed";
}).get();
I was expecting GenericRequestResponseResponder::``handleRequestResponse fired when the server sends the request, but client output is empty

boost/asio: Very simple chat server can't access the messages that are recieved

I am learning about boost and was messing around with its server and client communication to make a simple chat server, where anything that a client sends, is just displayed on the server. The server itself doesn't send anything and starts the receiving part. It is pretty straight-forward.
Server code:
#include <boost\asio\placeholders.hpp>
#include <boost\bind.hpp>
#include <boost\asio\ip\tcp.hpp>
#include <boost\asio\io_context.hpp>
#include <iostream>
class Server
{
private :
boost::asio::ip::tcp::socket server_socket;
boost::asio::ip::tcp::endpoint server_endpoint;
boost::asio::ip::tcp::acceptor acceptor;
std::string msg;
public :
Server(boost::asio::io_context &io) :
server_socket(io),
server_endpoint(boost::asio::ip::make_address("127.0.0.1"), 27015),
acceptor(io, server_endpoint)
{
acceptor.async_accept(server_socket,
boost::bind(&Server::async_acceptor_handler, this,
boost::asio::placeholders::error));
}
void async_acceptor_handler(const boost::system::error_code &ec)
{
if (!ec)
{
std::cout << "One client connected...\n";
server_socket.async_read_some(boost::asio::buffer(msg),
boost::bind(&Server::async_read_some_handler, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "async_acceptor failed with error code : " << ec.value() << std::endl;
std::cout << "Error description : " << ec.message() << std::endl;
}
}
void async_read_some_handler(const boost::system::error_code &ec)
{
if (!ec)
{
std::cout << msg << std::endl;
server_socket.async_read_some(boost::asio::buffer(msg),
boost::bind(&Server::async_read_some_handler, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "async_acceptor failed with error code : " << ec.value() << std::endl;
std::cout << "Error description : " << ec.message() << std::endl;
}
}
};
int main()
{
boost::asio::io_context io;
Server s(io);
io.run();
return 0;
}
In the client part, it is again a pretty straight-forward code, simply connects to the server and starts taking input from user and sends to server.
Client code:
#include <boost\asio\placeholders.hpp>
#include <boost\bind.hpp>
#include <boost\asio\ip\tcp.hpp>
#include <boost\asio\io_context.hpp>
#include <iostream>
class Client
{
private :
boost::asio::ip::tcp::socket client_socket;
boost::asio::ip::tcp::endpoint server_endpoint;
std::string msg;
public :
Client(boost::asio::io_context &iocontext) :
client_socket(iocontext),
server_endpoint(boost::asio::ip::make_address("127.0.0.1"), 27015)
{
//connect to server endpoint
client_socket.async_connect(server_endpoint,
boost::bind(&Client::async_connect_handler, this,
boost::asio::placeholders::error));
}
void async_connect_handler(const boost::system::error_code &ec)
{
if (!ec)
{
std::cout << "Connected to chat server...\n";
//wait for user input
std::cin >> msg;
std::cout << "\rC : " << msg << std::endl;
client_socket.async_write_some(boost::asio::buffer(msg),
boost::bind(&Client::async_write_some_handler, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "async_connect failed with error code : " << ec.value() << std::endl;
std::cout << "Error description : " << ec.message() << std::endl;
}
}
void async_write_some_handler(const boost::system::error_code &ec)
{
//wait for user input
std::cin >> msg;
std::cout << "\rC : " << msg << std::endl;
client_socket.async_write_some(boost::asio::buffer(msg),
boost::bind(&Client::async_write_some_handler, this,
boost::asio::placeholders::error));
}
};
int main()
{
boost::asio::io_context io;
Client c(io);
io.run();
return 0;
}
Now the problem:
It works fine, and connects to the server too. I get the proper "Connected to chat server..." in client and "One client connected..." in server. The problem arises after that :
In the server console, after the "One client" message, it just starts printing nothing and goes on and on.
The messages sent by the client are never showed in the server console.
Problem 1 can be a issue on my part as I am yet to check the wait functions and other calls which make the server wait. If you can guide me on that, it will be more than amazing. But the major problem is the part 2 of the problem, since, I have no idea why the server is always receiving nothing from client.
PS: This is an incomplete code and I plan to play a bit more with it, so, if there are some major flaws, please tell me so... :)
PPS: Before you say check other questions similar to this, I went through all the similar questions. For ex: this and this, but this are not relevant.
What is the size of string msg in the server side? It is 0. So the server reads always 0 bytes.
When you want to read to string and you call buffer::asio::buffer string must have some size, for example 10. It means you want to read 10 bytes into msg. You can call msg.resize(10) (before reading operation is initiated), then some data will be read into msg by async_read_some (it could be 1,2 bytes, whatever - it is how async_read_some works, but the maximum read characters is 10). But it is poor solution.
You are sending text, so you may consider using read data into streambuf instead of string, when you don't know how many bytes can come from the client side. Then you can call async_read_until with delimiter - it can be for example new line character.
Another solution is to use dynamic buffer. Where data is appened into string and you don't care about the initial size of string buffer. But dynamic buffer doesn't work with member functions of socket like async_read_some, it could be used with async_read as free function.

POCO websocket messes after 50 minutes of working

I have the following question related to POCO library. My client listens the messages from our backend server using POCO library. All is well the first 50 minutes, then with the socket happens something strange and method "receiveFrame" begins to return an exception. After that, the socket does not become operational. I have made few tests the time after which I receive not operational socket is exactly 50 minutes. Also I need to note that our backend server doesn't send anything during all time. I have no idea what happens... Below is code of our Handshake and Read procedures:
void WebSocketManager::Handshake()
{
qDebug() << "WebSocketManager::Handshake";
try {
HTTPResponse response;
QString origin = Settings::Instance()->GetErPortal();
QString host = origin.remove("http://");
host = host.remove('/');
QString token = "/event/bus/ws/subscribe?auth_token=" + Settings::Instance()->token().toUtf8();
_wssession.setHost(host.toUtf8().constData());
_wssession.setPort(80);
HTTPRequest request(HTTPRequest::HTTP_GET, token.toUtf8().constData(),HTTPMessage::HTTP_1_1);
request.set("origin", origin.toUtf8().constData());
_wssock = new WebSocket(_wssession, request, response);
response.getStatus();
HTTPResponse::HTTPStatus status = response.getStatus();
qDebug() << "Handshake status is : " << status;
if(status == HTTPResponse::HTTPStatus::HTTP_SWITCHING_PROTOCOLS)
_status = true;
}
catch (std::exception &e)
{
qDebug() << "WebSocketManager::Handshake exception " << e.what();
}
}
void WebSocketManager::Read()
{
char receiveBuff[1024];
while(_status)
{
qDebug() << "WebSocketManager::Read wait data...., thread = " << QThread::currentThread();
try {
int flags=0;
int rlen=_wssock->receiveFrame(receiveBuff,1024,flags);
if(!rlen)
{
qDebug() << "WebSocketManager::Read error";
emit ConnectionFailed();
return;
}
else
{
qDebug() << "WebSocketManager::Read, len =" << rlen << ", flags = " << flags << ", data = " << receiveBuff;
ProcessBackendEvent(QString(receiveBuff));
}
}
catch (std::exception &e)
{
qDebug() << "WebSocketManager::Read exception " << e.what();
}
}
}
It seems it is bug of POCO library described here https://github.com/pocoproject/poco/issues/490
On 1.9.0 POCO library all work fine...

How to parse json data from websocket_client using cpprestsdk

I'm connecting to a WebSocket whom always replies in JSON. I see there is an extract_string method for websocket_incoming_message however after trying numerous things with json:value it seems as though you can only construct JSON arrays on-the-fly by inserting key-value pairs one-by-one. Am I missing something here or is there a way to take the output from websocket_incoming_message and directly convert it into a json:value array?
websocket_client client;
//start socket connection to server
try {
std::cout << "s
----------
client.connect(U("wss://XZXXXZZy.com/ws?account_id=4de3f308f2f8d3247As70228f94e0d2aAea&ws_key=reception")).wait();
}
catch (const std::exception&e)
{
std::cout << e.what() << std::endl;
}
//send messages to the server
//websocket_outgoing_message msg;
//msg.set_pong_message();
//std::cout << "\n...........2nd.........;";
//std::string data = "hii";
//client.send(msg).then([]() {
//
//
//
//
// /* Successfully sent the message. */ });
//std::cout << " Successfully sent the message.";
//std::cout << "\n...........3rd.........;";
//receive messages from the server
client.receive().then([](websocket_incoming_message msg) {
std::cout << "receiving data from socket";
return msg.extract_string();
}).then([](std::string body) {
//FETCHING THE DATA FROM BODY. "TEXT/JSON"
std::cout << "displaying the data";
std::cout << body << std::endl;
const json::value& v1 = body.substr;
utility::string_t jsonval = v1.serialize();
auto array = v1.at(U("rows")).as_array();
for (int i = 0; i<array.size(); ++i)
{
auto id = array[i].at(U("id")).as_string();
std::wcout << "\n" << id;
auto key = array[i].at(U("key")).as_string();
std::wcout << "\n" << key;
auto array2 = array[i].at(U("value")).as_array();
std::wcout << array2[0];
std::wcout << array2[1];
}
}
);
//close the connection
client.close().then([]() {
std::cout << "successfully close socket connction";
/* Successfully closed the connection. */
});
I have json response in my string body.but i dont know how to parse json data from websocket responses event. i want to display contacts from api responses.please help me..
MY JSON RESPONSES
--------------------------------------
.{"action":"refresh_dashboard","data":{"users_list":[{"user_id":"901e6076ff351cfc2195fb86f8438a26","extensions":["1002"],"name":"Karthik M"},{"user_id":"cc3f94ecc14ee9c55670dcde9adc1887","extensions":["1006"],"name":"Rounak S Kiran"},{"user_id":"6c29ebdb34e1761fdf9423c573087979","extensions":["1003"],"name":"Amar Nath"},{"user_id":"74d5b5a9aca1faa4c2f217ce87b621d8","extensions":["1008"],"name":"Robin Raju"},{"user_id":"a7ad7e73bf93ea83c8efdc1723cba198","extensions":["1007"],"name":"Arshad Arif"},{"user_id":"b55146df593ec8d09e5fe12a8a4c1108","extensions":["1001"],"name":"Rahib Rasheed"},{"user_id":"3258f7ae4ae1db60435cbcf583f64a89","extensions":["1009"],"name":"Test User"},{"user_id":"90bc84e5e8a3427fe35e99bd4386de95","extensions":["1010"],"name":"Prince T"},{"user_id":"b501ef5b270a196afc0eed557ca74237","extensions":["1005","+17325951060"],"name":"Jineed AJ"},{"user_id":"1422af351e06adeab2de92f5a633a444","extensions":["1004"],"name":"Ashok PA"}],"busy_users":[],"reg_users":[{"user_id":"cc3f94ecc14ee9c55670dcde9adc1887","status":"registered"},{"user_id":"901e6076ff351cfc2195fb86f8438a26","status":"registered"},{"user_id":"1422af351e06adeab2de92f5a633a444","status":"registered"},{"user_id":"3258f7ae4ae1db60435cbcf583f64a89","status":"registered"},{"user_id":"b55146df593ec8d09e5fe12a8a4c1108","status":"registered"},{"user_id":"6c29ebdb34e1761fdf9423c573087979","status":"registered"}],"contacts":[{"owner_id":"cc3f94ecc14ee9c55670dcde9adc1887","status":"ready"},{"owner_id":"901e6076ff351cfc2195fb86f8438a26","status":"ready"},{"owner_id":"1422af351e06adeab2de92f5a633a444","status":"ready"},{"owner_id":"3258f7ae4ae1db60435cbcf583f64a89","status":"ready"},{"owner_id":"b55146df593ec8d09e5fe12a8a4c1108","status":"ready"},{"owner_id":"6c29ebdb34e1761fdf9423c573087979","status":"ready"}]}}
I got the complete solution .please try to use boost pacakges from nuget. The documentation will help you to parse the json data from string. I think jsoncpp is not an updated packages available in the nuget.so please try boost packages available in the nuget.
MYJSON STRING
{"action":"refresh_dashboard","data":{"users_list":[{"user_id":"901e6076ff351cfc2195fb86f8438a26","extensions":["1002"],"name":"Karthik M"},{"user_id":"7d617ef5b2390d081d901b0d5cd108eb","extensions":["1015"],"name":"Synway User2"},{"user_id":"c8f667f7d663e81f6e7fa34b9296f067","extensions":["1012"],"name":"Rahib Video"},{"user_id":"cc3f94ecc14ee9c55670dcde9adc1887","extensions":["1006"],"name":"Rounak S Kiran"},{"user_id":"6c29ebdb34e1761fdf9423c573087979","extensions":["1003"],"name":"Amar Nath"},{"user_id":"8e15c2d95d4325cb07f0750846966be8","extensions":["1011"],"name":"TLS User"},{"user_id":"2fc4142bdacf83c1957bda0ad9d50e3d","extensions":["1014"],"name":"Synway User1"},{"user_id":"74d5b5a9aca1faa4c2f217ce87b621d8","extensions":["1008"],"name":"Robin Raju"},{"user_id":"a7ad7e73bf93ea83c8efdc1723cba198","extensions":["1007"],"name":"Arshad Arif"},{"user_id":"b55146df593ec8d09e5fe12a8a4c1108","extensions":["1001"],"name":"Rahib Rasheed"},{"user_id":"391391de005a8f5403c7b5591f462ea1","extensions":["1013"],"name":"Sangeeth J"},{"user_id":"3258f7ae4ae1db60435cbcf583f64a89","extensions":["1009"],"name":"Aby TL"},{"user_id":"90bc84e5e8a3427fe35e99bd4386de95","extensions":["1010"],"name":"Prince T"},{"user_id":"b501ef5b270a196afc0eed557ca74237","extensions":["1005"],"name":"Jineed AJ"},{"user_id":"1422af351e06adeab2de92f5a633a444","extensions":["1004"],"name":"Ashok PA"}],"busy_users":[],"reg_users":[{"user_id":"901e6076ff351cfc2195fb86f8438a26","status":"registered"},{"user_id":"6c29ebdb34e1761fdf9423c573087979","status":"registered"}],"contacts":[{"owner_id":"901e6076ff351cfc2195fb86f8438a26","status":"ready"},{"owner_id":"6c29ebdb34e1761fdf9423c573087979","status":"ready"}]}}
CODES
client.receive().then([](websocket_incoming_message msg) {
std::cout << "receiving data from socket";
// msg.message_type();
return msg.extract_string();
//1..i have one string
//cout<<"\n///////////test"<< msg.extract_string().get().c_str();
// // 2.convert to json array
//json::value::parse( ::to_string_t(msg.extract_string().get()))
//
}).then([](std::string body) {
//std::cout << "displaying the data";
std::cout << body << std::endl;
std::string ss = body;
ptree pt;
std::istringstream is(ss);
read_json(is, pt);
std::cout <<"\n 1st"<< "action: " << pt.get<std::string>("action") << "\n";
std::cout <<"\n 2nd"<< "data: " << pt.get<std::string>("data") << "\n";
std::cout << "--------------------------------------------------------------";
for (auto& e : pt.get_child("data.users_list")) {
std::cout << "\n" << "users id " << e.second.get<std::string>("user_id") << "\n";
}
});
useful resources
Parse JSON array as std::string with Boost ptree
C++ boost parse dynamically generated json string (not a file)

zeromq / zmqpp : Forward metadata with message

With zmq and zmqpp, I am looking for a way to forward meta-data along with the message it belong. The goal is to get the 'User-Id' in a worker behind a load balancer which own the secure socket.
Here is a simple example, you can see the metadata disappear after being forwarded. I am not sure: is this metadata 'vanishment' a bug or a feature? Is there any workaround?
#include "zmqpp/zmqpp.hpp"
#include "zmqpp/curve.hpp"
int main()
{
zmqpp::curve::keypair client_keypair = zmqpp::curve::generate_keypair();
zmqpp::curve::keypair server_keypair = zmqpp::curve::generate_keypair();
std::cout << "Client Public Key: " << client_keypair.public_key << std::endl;
std::cout << "Server Public Key: " << server_keypair.public_key << std::endl;
zmqpp::context context;
zmqpp::auth authenticator(context);
authenticator.set_verbose(false);
authenticator.configure_curve(client_keypair.public_key);
zmqpp::socket curve_rep(context, zmqpp::socket_type::rep);
curve_rep.set(zmqpp::socket_option::curve_server, true);
curve_rep.set(zmqpp::socket_option::curve_secret_key, server_keypair.secret_key);
curve_rep.bind("tcp://127.0.0.1:4242");
zmqpp::socket curve_req(context, zmqpp::socket_type::req);
curve_req.set(zmqpp::socket_option::curve_server_key, server_keypair.public_key);
curve_req.set(zmqpp::socket_option::curve_public_key, client_keypair.public_key);
curve_req.set(zmqpp::socket_option::curve_secret_key, client_keypair.secret_key);
curve_req.connect("tcp://127.0.0.1:4242");
zmqpp::socket internal_rep(context, zmqpp::socket_type::rep);
internal_rep.bind("inproc://clear");
zmqpp::socket internal_req(context, zmqpp::socket_type::req);
internal_req.connect("inproc://clear");
{
zmqpp::message msg;
msg << "Hello";
curve_req.send(msg);
}
{
zmqpp::message msg;
curve_rep.receive(msg);
// read User-Id
std::string user_id;
std::cout << "- Before forward: ";
if (msg.get_property("User-Id", user_id))
std::cout << user_id << std::endl;
else
std::cout << "No user id" << std::endl;
// Forward message
internal_req.send(msg);
}
{
zmqpp::message msg;
internal_rep.receive(msg);
// read User-Id
std::string user_id;
std::cout << "- After forward: ";
if (msg.get_property("User-Id", user_id))
std::cout << user_id << std::endl;
else
std::cout << "No user id" << std::endl;
std::string content;
msg >> content;
std::cout << "- Message: " << content << std::endl;
}
{
zmqpp::message msg;
msg << "world !";
internal_rep.send(msg);
}
{
zmqpp::message msg;
internal_req.receive(msg);
// Forward message
curve_rep.send(msg);
}
{
zmqpp::message msg;
curve_req.receive(msg);
std::cout << "- Message: " << msg.get<std::string>(0) << std::endl;
}
return 0;
}
Output:
Client Public Key: }-}3(fH/r!I/9*tJX0bN/TT]Y2Qd#{IqszYzBX.g
Server Public Key: !#kpBlDrmW#e3jW)q6FumkKGjv#7lU?y9mD(QWd8
auth: Starting ZAP Authentication Server
- Before forward: }-}3(fH/r!I/9*tJX0bN/TT]Y2Qd#{IqszYzBX.g
- After forward: No user id
- Message: Hello
- Message: world !
auth: Shutdown ZAP Authentication Server
This can be a confusing element of ZMQ. The meta-data to which you are referring is not a part of the ZMQ message itself, it's part of the connection over which you received that message. The fact that you can access it as a property of that message is an artifact of the ZMQ wireline protocol, how data is transferred from one socket to another with all of the information that the receiving socket needs to appropriately process that message. A ZMQ message has no "headers" per se, it just has "frames", and the ZMQ sockets know how to handle those frames when they include metadata.
So, the short answer is that the sockets, being given details to negotiate the Curve crypto, send crypto metadata along with the message and the receiving socket, being set up with crypto details, knows what to do with that meta data. When you send it over "normal" sockets with no crypto, that metadata is stripped. If the backend pair of sockets used crypto, it would no longer have the metadata that applied to the frontend, it would have a User-Id that applied to the broker backend socket.
If you want to add the metadata to the message so it gets sent back to the backend, you'll have to append it to the message data, either directly or in a new message frame (multi-part message) and handle it yourself, it won't be metadata anymore it'll be first-class data.