Send request from a server to a connected client with RSocket C++ - 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

Related

How to Send messages between server and client using C++ standard library networking TS

I have tried following the tutorial from boost, however the API is not identical so I have had to guess some parts.
My attempt so far is shown bellow:
#include <iostream>
#include <experimental/internet>
#include <experimental/socket>
#include <thread>
#include <chrono>
using namespace std::experimental;
int main(int argc, char* argv[])
{
std::thread server = std::thread([]()
{
std::cout << "Starting server" << std::endl;
net::io_context context;
net::ip::tcp::endpoint endpoint{net::ip::tcp::v4(), 1234};
net::ip::tcp::acceptor acceptor{context, endpoint};
acceptor.non_blocking(true);
std::cout << "opened server on " << endpoint << std::endl;
std::error_code error;
net::ip::tcp::socket socket(context);
while (true)
{
socket = acceptor.accept(error); //accept connections
if (!error) //if connected with a client
{
std::cout << "Connected to client!" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::string data = "Hello World!";
net::const_buffer buf(&data, sizeof(data));
socket.send(buf);
std::cout << "Sent data!" << std::endl;
while(true) {}
}
}
});
std::thread client = std::thread([]()
{
net::io_context context;
net::ip::tcp::socket socket(context);
net::ip::tcp::endpoint server{net::ip::tcp::v4(), 1234};
std::error_code error;
while(true)
{
socket.connect(server, error); //attempt to connect
if (!error) //if connected
{
std::cout << "Connected to server!" << std::endl;
net::mutable_buffer buf;
while(buf.size() == 0)
{
socket.receive(buf);
}
std::cout << "Received data!" << std::endl;
std::cout << buf.data() << std::endl;
while(true) {}
}
}
});
server.join();
return 0;
}
The sever and client connect, but the message is not received by the client. The output from the program above is:
Starting server
opened server on 0.0.0.0:1234
Connected to server!
Connected to client!
Sent data!
And then it waits forever.
How do I get the socket to correctly receive the data?
This
std::string data = "Hello World!";
net::const_buffer buf(&data, sizeof(data));
is wrong. You want to send content of data string, not its internal bytes. &data gives you a pointer to underlying data of string instance, not its content. If you want to create buffer which represents content of data you can do:
const std::string data = "Hello World!";
net::const_buffer buf = net::buffer(data);
This
net::mutable_buffer buf;
while(buf.size() == 0)
{
socket.receive(buf);
}
gives you infinite loop because initial size of buf is 0, so receive reads 0 bytes and returns. Then while condition is checked, buf's size is still 0, and the loop goes on.
Before calling receive you need to specify the size of buffer - it indicates how many bytes must be read. You are sending Hello World! so
std::string msg;
msg.resize(12); // prepare space for incoming data
net::mutable_buffer buf = net::buffer(msg);
socket.receive(buf);
std::cout << "I got: " << msg << std::endl;

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...

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

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.

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)

Send and receive in different sockets in UDP

Later in my application I will have three threads: one thread that listen data on a port, one thread that send the data to an address on the same port. The last one is not important here.
For the moment, I don't use threads, I just want to do some tests.
My problem is the following :
If I just use the server to send and receive data, there is no problem. But when it is the client that send the data, it's like the distant peer did not receive anything.
My code for server :
#include "server.h"
using namespace boost::asio::ip;
using Peer = udp::endpoint;
Server::Server(boost::asio::io_service& io_service, Peer peer, Agent& agent) :
socket_(io_service, Peer(boost::asio::ip::udp::v6(), peer.port())),
recv_buffer_(), send_buffer_(), root_(peer), agent_(agent)
{
/* //when this is uncomment, that works fine
BOOST_LOG_TRIVIAL(info) << "Server Initialisation:";
std::shared_ptr<PeersReq> peersreq(new PeersReq());
std::vector<std::shared_ptr<Tlv>> tlv_vector;
tlv_vector.push_back(peersreq);
Packet packet(tlv_vector);
write_log(packet, peer);
boost::asio::streambuf request;
std::ostream os(&request);
packet.format(os);
std::cout << peer.address() << std::endl;
int n = static_cast<int>(socket_.send_to(request.data(),peer));
BOOST_LOG_TRIVIAL(debug) << "Bytes sent: " << n << std::endl;
*/
}
void Server::write_log(Packet packet, Peer peer) {
BOOST_LOG_TRIVIAL(info) << "Packet send to " << peer.address().to_string() << ":" << peer.port() << std::endl;
BOOST_LOG_TRIVIAL(info) << "Packet\n" << packet << std::endl;
}
void Server::receive() {
Peer peer;
BOOST_LOG_TRIVIAL(info) << "Now listening on port:" << root_.port() << std::endl;
socket_.receive_from(boost::asio::buffer(recv_buffer_), peer);
BOOST_LOG_TRIVIAL(info) << "Packet received" << std::endl;
std::cout << static_cast<int>(recv_buffer_[0]) << std::endl;
std::cout << static_cast<int>(recv_buffer_[1]) << std::endl;
if (recv_buffer_[0] != 57) //TO DO magic number
exit(EXIT_FAILURE); //Change this to send a bad
else if(recv_buffer_[1] != 0) //TO DO magic number
exit(EXIT_FAILURE);
uint16_t packet_length = static_cast<uint16_t>((recv_buffer_[2]<<8)+recv_buffer_[3]);
std::cout << packet_length << std::endl;
if (packet_length > 1024) //TODO magic number
exit(EXIT_FAILURE);
//maybe log ?
for(int i = 0 ; i < packet_length ; i++)
std::cout << i << ":" << (static_cast<int>(recv_buffer_[i+4]) & 0xFF) << std::endl;
Packet packet = Packet::from_string(recv_buffer_.data()+4, packet_length);
std::cout << "packet received" << std::endl;
std::cout << packet << std::endl;
//agent_.notify(packet, peer);
/*
boost::asio::streambuf request;
std::ostream os(&request);
packet_to_send.format(os);
//std::cout << request.size() << std::endl;
socket_.send_to(request.data(), peer);
*/
receive();
}
And the code for my client is the following :
Client::Client(boost::asio::io_service& io_service, Peer peer) : socket_(io_service, Peer(boost::asio::ip::udp::v6(), peer.port())) , peers_(), queue_peer_() {
//socket_.open(boost::asio::ip::udp::v6());
peers_.insert(peer);
queue_peer_.insert(std::make_pair(peer.address().to_string(),std::vector<std::shared_ptr<Tlv>>()));
std::shared_ptr<PeersReq> peersReq(new PeersReq());
add_tlv_to_queue(peersReq, peer);
send();
}
void Client::add_tlv_to_queue(std::shared_ptr<Tlv> tlv, Peer peer) {
if(queue_peer_.find(peer.address().to_string())!= queue_peer_.end()) {
peers_.insert(peer);
queue_peer_.insert(std::make_pair(peer.address().to_string(),std::vector<std::shared_ptr<Tlv>>()));
}
queue_peer_.find(peer.address().to_string())->second.push_back(tlv);
}
void Client::send() {
for ( std::unordered_map<std::string, std::vector<std::shared_ptr<Tlv>>>::iterator it = queue_peer_.begin(); it != queue_peer_.end(); ++it ) {
if(it->second.size()>0) {
boost::asio::streambuf request;
std::ostream os(&request);
Packet packet(it->second);
packet.format(os);
Peer peer = get_peer_from_string(it->first);
std::cout << peer.address() << std::endl;
int n = static_cast<int>(socket_.send_to(request.data(),peer));
}
}
}
Peer Client::get_peer_from_string(std::string string) {
Peer peer;
for(std::set<Peer>::const_iterator it =peers_.begin() ; it != peers_.end() ; it++) {
if(it->address().to_string() == string)
peer=*it;
}
//undefined behaviour if the peer is not registred. But it shouldn't happen
return peer;
}
In the main I use the following code :
Agent agent(storage, peer);
Server server(io_service_server, peer, agent);
Client client(io_service_client, peer);
server.receive();
I don't know if I did something bad or there is something special to get this behviour.
EDIT :
This is a snippet :
#include<array>
#include<boost/asio.hpp>
#include<iostream>
using Peer = boost::asio::ip::udp::endpoint;
using namespace boost::asio::ip;
class Server {
public:
Server(boost::asio::io_service& io_service, Peer peer);
void receive();
private:
boost::asio::ip::udp::socket socket_;
std::array<char, 1024> recv_buffer_;
};
Server::Server(boost::asio::io_service& io_service, Peer peer) :
socket_(io_service, Peer(boost::asio::ip::udp::v6(), peer.port())),
recv_buffer_()
{
boost::asio::streambuf request;
std::ostream os(&request);
os << "Server";
int n = static_cast<int>(socket_.send_to(request.data(),peer));
}
void Server::receive() {
Peer peer;
socket_.receive_from(boost::asio::buffer(recv_buffer_), peer);
std::cout << static_cast<int>(recv_buffer_[0]) << std::endl;
receive();
}
class Client {
public:
Client(boost::asio::io_service& io_service, Peer peer);
void send(Peer peer);
private:
boost::asio::ip::udp::socket socket_;
};
Client::Client(boost::asio::io_service& io_service, Peer peer) : socket_(io_service) {
socket_.open(boost::asio::ip::udp::v6());
send(peer);
}
void Client::send(Peer peer) {
boost::asio::streambuf request;
std::ostream os(&request);
os << "Client";
int n = static_cast<int>(socket_.send_to(request.data(),peer));
}
int main(int argc, char* argv[]) {
boost::asio::io_service io_service_client;
boost::asio::io_service io_service_server;
Peer peer;
peer.address(); //Add an address here
peer.port(12345);
Client client(io_service_client, peer);
Server server(io_service_server, peer);
return 0;
}