-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
questions about the scs #3
Comments
Honestly, I never really thought of utilizing multiple clients in a single process. I think it should be possible in theory, but it hasn't really been tested. I'll start by seeing if this works in a simple test, and go from there. As far as passing data... the SCS API just passed buffers of data. So you'll need to create some sort of high-level protocol yourself to understand what a "string" is on the server. This can be as simple as a simple number or enumeration that acts as a "message type", which then interprets the bytes that come in. This is up to the application to figure out. |
I've added some tests to make sure the system works with multiple clients in a single process. So far it seems like there's no problem with that. |
thanks, |
For example, this code interrupts my pipeline and unable to consume data in class SenderStage : public BaseStage {
public:
SenderStage(std::string port)
{
// callback to get data, that need to be send to the client
set_consuming_callback([this](const boost::any& data) {
results = boost::any_cast<std::list<string>>(data);
if (!results.empty()) {
need_send = true;
}
}
// ...
auto server = CreateServer(params);
std::optional<ClientID> server_clientId;
// Handler for incoming data
server->OnReceiveData([&](IServer& server, ClientID clientId, const void* data, size_t bytes)
{
std::string str((const char*)data, bytes);
if (str == "start") { server_clientId = clientId; }
else if (str == "stop") { server_clientId = std::nullopt; }
});
// Handler for per-cycle update
server->OnUpdate([&](IServer& server)
{
if (server2_clientId.has_value())
{
if (need_send)
{
std::string res = results[0];
server.Send(server2_clientId.value(), res.data(), res.size());
need_send = false;
}
}
});
// Start listening for client connections
server->StartListening();
// Wait until ESC is pressed
while (GetChar() != 27) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); }
}
private:
std::list<string> results;
bool need_send = false;
} |
So, first of all, I should point out that you can't serialize a list of strings across a network connection simply by casting it to bytes. That's going to crash horribly. Look for a serialization library to help with that (Boost has one), and I think "cereal" is somewhat popular too. Basically, the multi-threaded nature of SCS clients and servers is mostly handled for you. You're just providing callback handlers that either get called on connection or receiving data. It also provides handlers for periodic updates, which is useful if you want to do things like time-based logic, or responses to things other than receiving data. As you indicated, each connection operates it's own thread. This is a simple system architecturally-speaking, but not very efficient if you want to build servers that handle huge numbers of simultaneous connections. In the modified example, the only reason this code blocks is because of the while (GetChar() != 27) loop, which is simply waiting for ESC to be pressed. When a client connects to the server, notice that there's a ClientID passed as a parameter. Each new client will have it's own ID, so you can use this in the server code to identify individual clients. Remember, these callback functions are being called from background threads, so you'll need to protect your shared data structures with locks to make them thread-safe. So, if I was writing complex server logic with multiple stages or other state to track per-client, I'd create a map of client IDs to state data. And remember, you'll have to create a lock each time you read for write from this map data on the server. You can then store any state data you need in the map data, like the current stage. |
Thanks, in this example I have send a string instead a list of strings, I want to deal with the threads and connections, and later send proper data. Is it acceptable to send a std::string in the manner I am currently doing ? the server doesn't have many clients, it is just one. The applications (that I want to send data between) have backend-frontend relations — 3 type of data will be send in the 3 connections (an original frame, results of an algorithm, and json settings) I have understood, the Is it desired to have CreateServer() and Server Handlers in separate std::thread, |
So, std::string can't be sent as-is across the wire as-is either. Again, this is what serialization libraries are for. Any container that internally contains a pointer to data is going to have this same issue. Remember, on the receiving end, all you have is a series of bytes. So for a string, you'll want to first make sure it's identified as a string via some message or type ID. You'll probably then need to get the length of the string, and then finally, you'll know how long the string is and can get the data, and convert this back into a std::string. If you need the server to stay active over time, you can use the OnUpdate() handler. This code gets called roughly every millisecond. There's probably no need to launch multiple threads yourself (unless those are needed for some sort of processing), but you do have to make sure the handlers are thread-safe themselves. I think you're mentally over-complicating what you need to do, as far as I can tell from what you're describing. This is what's known as an event-driven architecture. Your code won't be linear - it just needs to respond to the events generated by the SCS Server and Client objects. Maybe I need to create a more complex example to really explain how this might work... |
How I can I make |
You could do this yourself with std::chrono, but it seems worthwhile to have a parameter to control this aspect of both client and server explicitly. I've added updateMs to the creation params of both client and server. Specify in milliseconds how frequently the update callback is called. For example, set the server params updateMs value to 1000 to have it tick once per second. Note that this is currently in the development branch only. |
Hello, are there default way to client close its connection on the server side in this library? |
It will be disconnected after timeout, but how to make client to request disconnect? |
Hello, I am trying to modify
scstest.cpp
to create multiplescs::clientPtrs
within a single client application. Each of these clients class will have a different logic and protocol and will request different data from the server.To make the question more specific, let's say that we want a client to send a string "String" in addition to the random data (as is the case in the current example) and receive the response "Answer" from the server every second. How can we implement this?
To start, I tried put the
scs::clientPtr
client inside an if(true){} statement, but the client stopped workinghttps://gist.github.com/yalov/1d73666029ca6e6fcaabacdef60db6cf
The text was updated successfully, but these errors were encountered: