I have a C++ gRPC client and Golang gRPC server. For a bi-directional stream, when the client wants to close the stream, it blocks forever on the call to Finish().
This only happens if there is no error, that is, the server rpc function returns nil. If the server was written in C++, I understand it would have returned Status::Ok.
If the Golang server returns a non-nil error, then the Finish() function returns as expected. The problem occurs only in the case of no error.
Example:
.proto
service StreamTest {
rpc Get(stream StreamCommand) returns (stream Result) {}
}
message StreamCommand{
string cmd = 1;
}
message Result {
string res = 1;
}
.cpp
std::unique_ptr<ClientReaderWriter<StreamCommand, Result>> readerWriter;
bool Get(Result &res) {
return readerWriter->Read(&res);
}
bool CloseClient() {
StreamCommand cmd;
cmd.set_cmd("stop");
readerWriter->Write(cmd);
readerWriter->WritesDone();
Status status = readerWriter->Finish(); // <------ BLOCKING
return status.ok();
}
I have tested the server with a Golang gRPC client and it works fine. Should the server return something other than a nil error? Should I report this as a bug?
Any help is appreciated! Thanks!
I am not familiar with Go, but I know c++ layer. Can you run the client with GRPC_VERBOSITY=debug and GRPC_TRACE=api? That would give more insight into the problem.
Related
I'm using GRPC to remote call the database and store the data in the response format given by the .proto file. My program is based on CPP programming:
// similar .proto file
message FinalResponse
{
repeated IntermediateResponse finals = 1;
}
message IntermediateResponse
{
string name = 1;
InitialResponse foo = 2;
}
enum InitialResponse
{
COUNTRY_UNKNOWN = 0;
COUNTRY_INDIA = 1;
}
For my case, the request message is empty(no field) so didn't displayed here. I went through the protocol buffer documentation and tried this:
// firstly called the database and stored the intermediateResponse in a vector<pair<string, string>> data
//pseudo-code below:
FinalResponse result;
for cur_data in data:
{
IntermediateResponse *interResp = result.add_finals();
interResp->set_name(cur_data.first);
interResp->set_foo(static_cast<InitialResponse>(cur_data.second));
}
When I'm executing this, there is no syntax/build error but grpc status is saying we didn't get any response back:
ERROR - (12) No message returned for unary request
I want to clarify that service was running from the server side and client is able to detect that service as well, I'm suspecting that maybe the returned data through database is not properly stored in the response message and so GRPC is deducing that we didn't get back any data. Please suggest some work around for this?
Looks like it was the server side issue probably, now with the same changes, it is able to store the response properly.
Maybe server went down for some time and returned error.
I'm trying to write an async tcp client(client should be capable of writing to the socket without waiting for previous operations' results to arrive).
std::future<void> AsyncClient::SomeMethod(sometype& parameter)
{
return std::async(
std::launch::async,
[&]()
{
// Gonna send a json. ';' at the end of a json separates the requests.
const std::string requestJson = Serializer::ArraySumRequest(numbers) + ';';
boost::system::error_code err;
write(requestJson, err);
write method:
void AsyncClient::write(const std::string& strToWrite, boost::system::error_code& err)
{
// m_writeMutex is a class member I use to synchronize writing.
std::lock_guard<std::mutex> lock(m_writeMutex);
boost::asio::write(m_socket,
boost::asio::buffer(strToWrite), err);
}
But result is not what I expected. mostly what I receive on server side is not a complete request followed by ;.
What happens is like:
A request: {"Key":"Value"};{"Key":"Va
Next request: lue"};{"Key":"Value"};
Why it's like this?
You need to actually implement the protocol on the receiving end. If you haven't received an entire request, you need to call your receive function again. The socket doesn't understand your application protocol and has no idea what a "request" is -- that's the job of the code that implements the application protocol.
If you haven't received a complete request, you need to receive more. The socket has on idea what a "complete request" is. If that's a complete JSON object, then you need to implement enough of the JSON protocol to find where the end of a request is.
I cannot get this simple test work. I wrote to the client in C++ and the server in NodeJS, both running on my computer. When I execute the client application, the console outputs this text...but the event 'key' is never fired on the server!
Client console output:
Error: No active session
[2019-11-21 17:30:11] [connect] Successful connection
[2019-11-21 17:30:11] [connect] WebSocket Connection 127.0.0.1:8081 v-2 "WebSocket++/0.8.1" /socket.io/?EIO=4&transport=websocket&t=1574353811 101
C++ client
#include "pch.h"
#include <iostream>
#include <sio_client.h>
using namespace sio;
using namespace std;
int main()
{
sio::client io;
io.connect("http://127.0.0.1:8081");
string command = "w";
io.socket()->emit("key", command );
}
NodeJS server
'use strict';
const express = require('express');
const app = express();
const serverHttp = require('http').Server(app);
const io = require('socket.io')(serverHttp);
const port = 8081;
io.on('connection', function (socket) {
// Never fired :(
socket.on('key', function (data) {
console.log("key received!!!");
});
});
serverHttp.listen(port, function() {
console.log("init!!!");
});
could you please fix this, I saw someone asking the same question in the GitHub issues section for socket io c++ client, no one has answered yet. please help out
From a brief look through the code it seems that io.connect starts a separate thread to do the networking. When it returns the socket is very likely still in a connecting state.
The code for .emit ends up here, which pushes a packet onto the queue and simply returns if the socket is not connected yet.
So I think the root cause of your problem is that the application exits before the network thread has had a chance to finish connecting.
The stupidest way to fix this is to simply add a sleep statement at the end of your main function, to give the network thread a chance to connect and get its message through. A slightly better way is to use socket.set_open_listener to get notified when the connection has been opened, and then send the message, because that should go through immediately:
sio::client io;
io.set_open_listener([&]() {
io.socket()->emit("key", command);
});
io.connect("http://127.0.0.1:8081");
This constructs and passes a lambda to set_open_listener, where it is stored as a std::function<void(void)> internally.
I am trying to build an asynchronous gRPC C++ client that sends/receives streaming messages to/from server using the ClientAsyncReaderWriter instance. The client and the server send messages to each other whenever they want. How can I check if there is any message from the server?
The ClientAsyncReaderWriter instance has a binded completion queue. I tried to check the completion queue by calling Next() and AsyncNext() functions to see if there is any event that would indicate that there is some message from the server. However, the completion queue has no events even if there is a message from the server.
class AsyncClient {
public:
AsyncClient(std::shared_ptr<grpc::Channel> channel) :
stub_(MyService::NewStub(channel)),
stream(stub_->AsyncStreamingRPC(&context, &cq, (void *)1))
{}
~AsyncClient()
{}
void receiveFromServer() {
StreamingResponse response;
// 1. Check if there is any message
// 2. Read the message
}
private:
grpc::ClientContext context;
grpc::CompletionQueue cq;
std::shared_ptr<MyService::Stub> stub_;
std::shared_ptr<grpc::ClientAsyncReaderWriter<StreamingRequest, StreamingResponse>> stream;
};
I need to implement steps 1 and 2 in the receiveFromServer() function.
Fortunately, I found a solution to my problem and the asynchronous bi-directional streaming in my project works as expected now.
It turned out that my understanding of the "completion queue" concept was incorrect.
This example was a great help for me!
so what I'm trying to do is understand how sockets work and how to make a simple server for communication between the server and the client application
I tried to accomplish this using AS3 with the project named Red Tamarin (Runs AS3 code on console but it doesn't really matter at the moment)
I managed to create a basic server, It's functionality is basically this:
creates a socket and activates these on it: listen() , accept(). when it accepts, it also adds the new socket received from the accept() to an array of connections.
a for loop that runs according to the length of the connections array and runs receive() on each socket (I didn't call listen() / accept() on those connections, should I?)
My actionscript 3 application connects to the server successfully,
And then for a testing purpose I decided to write() to the server from the client non-stop, just to make sure that the server really is getting the data so I can actually go further into adding more functionality..
But the server doesn't seem to get any further information at all..
It seems to respond only to connection / disconnection, but not really listening between them for any other info..
I know that showing my code would be better, but for now I'd like to know if I'm approaching this correctly, I read about it on the internet and it seems like I am but I came here just to make sure..
Thanks in advance!
EDIT:
I was requested for some of my code, here it is, well the most important parts at least
private var _connections:Array;
private var _socket:Socket;
private var _server:Client;
private var _running:Boolean;
private var _port:uint;
private var _address:String;
public function Server(address:String, port:uint)
{
_connections = [];
_address = address;
_port = port;
_running = false;
_socket = new Socket();
}
public function start():void {
_socket.bind(_port, _address);
_socket.listen(128);
_running = true;
_server = new Client(_socket);
_addClient(_server);
_start();
}
private function _start():void {
while (_running) {
_loop();
}
}
private function _addClient(client:Client):void {
_connections.push(client);
}
public function _loop():void
{
var i:uint;
var selected:Client;
var newconn:Socket;
for (i = 0; i < _connections.length; i++ ) {
selected = _connections[i];
if (selected.hasData()) {
if (selected == _server) {
//accept a new client connection
newconn = _socket.accept();
if (!newconn.valid){
//Invalid.
}
else {
//Add a new client
_addClient(new Client(newconn));
}
} else {
//Read data from clients
selected._socket.receive();
}
}
}
}
Just to answer your listen()/accept() question, you only need to call listen() once when the server is initially set up. Afterwards, you will need to execute accept() for each new client connection you want to make (as accept() will return a socket file descriptor that handles the new client).
After the client is accept()ed, then you will use the socket file descriptor of the client to receive() or send() any data.
look at this example
https://code.google.com/p/spitfire-and-firedrop/source/browse/trunk/socketpolicyd/src/spitfire/SocketPolicyServer.as
in your main loop from what I see in your code you only check if you can read the current socket, you need also to check if you can write to the current socket
also note that everyone has a socket handle, the server and the clients
my guess is you get a bit confused between the Server and Client classes that both wrap a Socket object, try to use only the Socket objects (as in the example above)
and when you understand that then you can go further and abstract/structure bigger classes