GithubHelp home page GithubHelp logo

Comments (18)

eidheim avatar eidheim commented on July 20, 2024

I have not had or heard of such an issue, so I would suspect the problem might be in your source code. If you do not figure it out, you can post a minimal example where this issue happens.

from simple-websocket-server.

Victordmdb avatar Victordmdb commented on July 20, 2024

Sorry, actually the issue seems like it creates a new connection on message. Is that normal behaviour? Here are prints of the pointers

Firefox stream : Streamed opened on connection 0x7f96c5f95ac0, on server 0x7ffd76bfb5f0
Chrome stream : Streamed opened on connection 0x7f96beffcac0, on server 0x7ffd76bfb5f0

Chrome message :Message received on connection 0x7f96c5f957f0, on server 0x7ffd76bfb5f0
Firefox message : Message received on connection 0x7f96bfffe7f0, on server 0x7ffd76bfb5f0

from simple-websocket-server.

Victordmdb avatar Victordmdb commented on July 20, 2024

Omg sorry no, the issue was with my code. Due to a shared variable.

from simple-websocket-server.

eidheim avatar eidheim commented on July 20, 2024

No worries, glad you figured it out.

from simple-websocket-server.

Victordmdb avatar Victordmdb commented on July 20, 2024

Though this is slightly related to my issue, how would one be able to recognize if a message is coming from the same computer as the onopen, or a previous onmessage? If there is a new connection for every message (is that actually supposed to happen?), it seems difficult to identify a unique source.

Is there some sort of unique identifier for the client?

from simple-websocket-server.

eidheim avatar eidheim commented on July 20, 2024

The connection should not close after a message is sent, the connection should be persistent until a close is called, or an error occurs.

from simple-websocket-server.

eidheim avatar eidheim commented on July 20, 2024

I created a really simple desktop streaming service for a hopeless lecture room at my university where I could not use a projector. The service shows how one can store connections though: https://github.com/eidheim/desktop-stream/blob/master/main.cpp

from simple-websocket-server.

Victordmdb avatar Victordmdb commented on July 20, 2024

I realise my confusion was because I was looking at the pointers to the connection, not the value itself. Which seems to be different. I'm running into this issue whereas lambda functions i'm using assigning in the onmessage which have a callback for send, are having their reference values reassigned each time there is a new connection.

That is, my first connection has ID 139765550680544, and the callback will initially send to that connection. But when a second connection appears eg 139765617789328, the callback for BOTH the first and second will use this ID 139765617789328.

from simple-websocket-server.

Victordmdb avatar Victordmdb commented on July 20, 2024

Aha! Nope, I've just realised it was my fault again. Sorry!

All my problems simply had to do with figuring out how to handle information associated with each connection, because I had just been using global objects.

Thanks for all the help!

from simple-websocket-server.

Victordmdb avatar Victordmdb commented on July 20, 2024

Actually, the error still seems to be appearing. I have creation a class to hold the information for each connection, inside an unordered_map, indexed with '(size_t)connection.get()'. When I receive a message I create a callback lambda expression which I pass to the class, which itself then initialises a thread with at will eventually call the callback.

Earlier I thought my function was reassigning a value to the lambda expression because I was just using one global class instead of creating a class for each connection. But it didnt fix the issue,

The lambda expression captures the connection ptr and server (by ref).

Then the issue as above happens. If I have 1 connection there is no problem. But if I add a second, the callback of the first connection starts using the id of the second connection. Its changing the captured variable. Am I misunderstanding how lambda functions work in threads?

from simple-websocket-server.

eidheim avatar eidheim commented on July 20, 2024

When you create a thread, make sure you capture copies of the connection objects instead of references. The references you are using might only be valid in the scope.

from simple-websocket-server.

eidheim avatar eidheim commented on July 20, 2024

You should maybe read up shared_ptr and memory management in C++. This is especially important when working with threads. Mostly we try to avoid this by running events in a single threaded application, like how UI libraries do it. You then also avoid mutex locks and unlocks. However, in cases where you have heavy work that needs to be done, one would pass this to a thread, but then it is important that the connection shared_ptr object is copied into the thread lambda through capturing.

from simple-websocket-server.

Victordmdb avatar Victordmdb commented on July 20, 2024

I'm trying to create unicast video streams for individual connections, hence the need for individual threads for each connection. It's a heavy workload. I believe I'm capturing the variables properly as well. Here's the overall code:

class MyClass {
     public:
        MyClass();
        ~MyClass();
        addCallback(std::function < void (std:string data) > callback);
        launch();
    private:
        std::function < void (std:string data) > callback;
}

MyClass::addCallback(callback){
    callback = callback;
}

MyClass::launch(){
    std::thread t = std::thread{ &MyFunct, callback };
    t.detach();
}

int main(int argc, char* argv[]){
  const int port = 8085;
  auto& stream = server.endpoint["^/stream/?$"];
  std::unordered_map<size_t, std::shared_ptr<MyClass>> MyClassList;

  stream.onmessage = [&server, &MyClassList ](std::shared_ptr<WsServer::Connection> connection, std::shared_ptr<WsServer::Message> message) {

     auto callback = [&server, connection, &MyClassList ]( std::string data) {
       printf("\n\nSending through connection id %zu\n\n" (size_t)connection.get());
      //This is overwritten by the last connection, ie when the thread initialised by the 1st connection calls this, the capture information is now that of the 2nd connection (if there are 2 connections)
     }
     MyClassList[(size_t)connection.get()].addCallBack(callback);
     MyClassList[(size_t)connection.get()].launch();
   }

     stream.onopen= [&MyClassList ](std::shared_ptr<WsServer::Connection> connection, std::shared_ptr<WsServer::Message> message) {
          MyClassList.emplace((size_t)connection.get(),  std::make_shared<MyClass>(connection));
     }

}

from simple-websocket-server.

eidheim avatar eidheim commented on July 20, 2024

Would you mind creating a complete minimal example that I can just paste into my ws_examples.cpp file? That is, just fix the above (add the needed includes as well) so that I can look how it looks in my IDE.

from simple-websocket-server.

eidheim avatar eidheim commented on July 20, 2024

Especially callback=callback; looks weird.

from simple-websocket-server.

Victordmdb avatar Victordmdb commented on July 20, 2024

I've tried setting it up with the WsClient, but the 2nd doest seem to connect.

#include "server_ws.hpp"
#include "client_ws.hpp"
#include <unordered_map>

using namespace std;

typedef SimpleWeb::SocketServer<SimpleWeb::WS> WsServer;
typedef SimpleWeb::SocketClient<SimpleWeb::WS> WsClient;

int MyFunct ( std::function < void (std::string data) > callback ){
  int loop = 0;
  while(true){
      callback("call loop "+std::to_string(loop ++));
      sleep(1);
  }
}


class MyClass {
     public:
        MyClass();
        ~MyClass();
        void addCallBack(std::function < void (std::string data) > callback);
        void launch();
    private:
        std::function < void (std::string data) > _callback;
};

MyClass::MyClass(){};
MyClass::~MyClass(){};

void MyClass::addCallBack( std::function< void (std::string data) > callback){
    _callback = callback;
}

void MyClass::launch(){
    cout << "Server: Launching Threaded function" << endl;
    std::thread t = std::thread{ &MyFunct, _callback };
    t.detach();
    cout << "Server: Succesfully launched thread" << endl;

}

int main() {
    //WebSocket (WS)-server at port 8085 using 1 thread
    WsServer server(8085, 5);

    auto& stream = server.endpoint["^/stream/?$"];
    std::unordered_map<size_t, std::shared_ptr<MyClass>> MyClassList;

    stream.onmessage = [&server, &MyClassList ](std::shared_ptr<WsServer::Connection> connection, std::shared_ptr<WsServer::Message> message) {

      auto message_str=message->string();
      cout << "Server: Message received: \"" << message_str << "\" from " << (size_t)connection.get() << endl;

      auto callback = [ connection ]( std::string data ) {
        cout << "Server Thread received callback request for connection "<< (size_t)connection.get()<< " : "<<data<<std::endl;
        //This is overwritten by the last connection, ie when the thread initialised by the 1st connection calls this, the capture information is now that of the 2nd connection (if there are 2 connections)
      };

      MyClassList[(size_t)connection.get()]->addCallBack(callback);
      MyClassList[(size_t)connection.get()]->launch();
    };

    stream.onopen = [&MyClassList](std::shared_ptr<WsServer::Connection> connection) {
      cout << "Server: Opened stream " << (size_t)connection.get() << endl;
      MyClassList.emplace((size_t)connection.get(),  std::make_shared<MyClass>());
    };


    thread server_thread([&server](){
        //Start WS-server
        server.start();
    });    

this_thread::sleep_for(chrono::seconds(1));

WsClient client1("localhost:8085/stream");
    client1.onopen=[&client1]() {
        cout << "Client1: Opened connection" << endl;

        string message="Hello";
        cout << "Client1: Sending message: \"" << message << "\"" << endl;

        auto send_stream=make_shared<WsClient::SendStream>();
        *send_stream << message;
        client1.send(send_stream);
    };





    WsClient client2("localhost:8085/stream");
    client2.onopen=[&client2]() {
        cout << "Client2: Opened connection" << endl;

        string message="Hello";
        cout << "Client2: Sending message: \"" << message << "\"" << endl;

        auto send_stream=make_shared<WsClient::SendStream>();
        *send_stream << message;
        client2.send(send_stream);
    };

    client1.start();
    this_thread::sleep_for(chrono::seconds(3));
    client2.start();

    server_thread.join();

    return 0;
}

from simple-websocket-server.

Victordmdb avatar Victordmdb commented on July 20, 2024

Arg, in this demo it works. It must be to do with my code somewhere then. Frustrating.

from simple-websocket-server.

Victordmdb avatar Victordmdb commented on July 20, 2024

Ok it is a deeper issue with my callback. Its because I'm passing it to a C function, and having trouble making it thread safe. I posted the issue here:
http://stackoverflow.com/questions/41198854/using-a-c-class-member-function-as-a-c-callback-function-thread-safe-version

from simple-websocket-server.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.