socket.io-client-cpp icon indicating copy to clipboard operation
socket.io-client-cpp copied to clipboard

Client automatically close after establishing connection

Open tai1235 opened this issue 4 years ago • 2 comments

I'm writing a client program to connect to a server with tls setup and listen for messages. The case is when the connection established, the OnClose callback was called after approximately 45s. When I connect to a localhost socket.io server without tls, this issue never happens.

Now I'm stuck and don't know why the problem occurs, please help.

Log:

[2021-09-08 09:03:04.939170] [0x0000000119693dc0] [info]    Connecting to host
[2021-09-08 09:03:04.939805] [0x0000000119693dc0] [debug]   Wait for connection to finish
[2021-09-08 09:03:05] [connect] Successful connection
[2021-09-08 09:03:05] [connect] WebSocket Connection 113.177.27.162:3335 v-2 "WebSocket++/0.8.2" /socket.io/?EIO=4&transport=websocket&t=1631066584 101
[2021-09-08 09:03:05.102168] [0x0000700007803000] [info]    OnConnected --> start
[2021-09-08 09:03:05.102197] [0x0000700007803000] [info]    OnConnected --> done
[2021-09-08 09:03:05.102252] [0x0000000119693dc0] [debug]   Connection finished
[2021-09-08 09:03:05.102445] [0x0000000119693dc0] [debug]   Namespace: /
[2021-09-08 09:03:50.143203] [0x0000700007803000] [info]    sio closed: normal

Server configuration:

const redisAdapter = require('socket.io-redis');
const io = require('socket.io')(server,{
    adapter: redisAdapter({ 
        host: process.env.REDIS_HOST, 
        port: process.env.REDIS_PORT, 
        key: process.env.REDIS_NAMESPACE
    })
});

Client code:

#include <string>
#include <mutex>

#include <unistd.h>

#include "sio_client.h"
#include "boost/log/trivial.hpp"

std::string PrintSocketIOMessage(const sio::message::ptr& message);
void OnConnected();
void OnClose(sio::client::close_reason const& reason);
void OnFail();
void OnError(sio::message::ptr const& message);
void BindEvents(const sio::socket::ptr& socket);

bool connection_finish = false;
std::mutex lock;
std::unique_lock<std::mutex> unique_lock(lock);
std::condition_variable cond;

int main(int argc, char** argv) {
    sio::client client;
    std::string host = argv[1];

    client.set_open_listener(&OnConnected);
    client.set_close_listener(&OnClose);
    client.set_fail_listener(&OnFail);
    client.connect(host);
    BOOST_LOG_TRIVIAL(info) << "Connecting to " << host;
    if (!connection_finish) {
        BOOST_LOG_TRIVIAL(debug) << "Wait for connection to finish";
        cond.wait(unique_lock);
    }
    BOOST_LOG_TRIVIAL(debug) << "Connection finished";
    BindEvents(client.socket());
    BOOST_LOG_TRIVIAL(debug) << "Namespace: " << client.socket()->get_namespace();

    while (true) {
        sleep(1);
    }

    BOOST_LOG_TRIVIAL(debug) << "Closing";
    client.sync_close();
    client.clear_con_listeners();
    return 0;
}

std::string PrintSocketIOMessage(const sio::message::ptr& message) {
    std::string result;
    switch (message->get_flag()) {
        case sio::message::flag_boolean: {
            result.append(message->get_bool() ? "true" : "false");
        } break;
        case sio::message::flag_integer: {
            result.append(std::to_string(message->get_int()));
        } break;
        case sio::message::flag_double: {
            result.append(std::to_string(message->get_double()));
        } break;
        case sio::message::flag_string: {
            result.append(message->get_string());
        } break;
        case sio::message::flag_array: {
            result.append("[ ");
            for (auto &it : message->get_vector()) {
                PrintSocketIOMessage(it);
                if (&it != &message->get_vector().back()) {
                    result.append(", ");
                }
            }
            result.append(" ]");
        } break;
        case sio::message::flag_object: {
            result.append("{ ");
            for (auto it = message->get_map().begin(); it != message->get_map().end(); ++it) {
                result.append(it->first).append(": ").append(PrintSocketIOMessage(it->second));
                if (it != std::prev(message->get_map().end())) {
                    result.append(", ");
                }
            }
            result.append(" }");
        } break;
        case sio::message::flag_binary: {
            result = "binary type";
        } break;
        case sio::message::flag_null: {
            result = "null type";
        } break;
    }
    return result;
}

void OnConnected() {
    BOOST_LOG_TRIVIAL(info) << "OnConnected --> start";
    connection_finish = true;
    cond.notify_all();
    BOOST_LOG_TRIVIAL(info) << "OnConnected --> done";
}

void OnClose(sio::client::close_reason const& reason) {
    BOOST_LOG_TRIVIAL(info) << "sio closed: " << (reason == sio::client::close_reason::close_reason_normal ? "normal" : "drop");
    exit(0);
}

void OnFail() {
    BOOST_LOG_TRIVIAL(info) << "sio failed";
    exit(0);
}

void OnError(sio::message::ptr const& message) {
    BOOST_LOG_TRIVIAL(info) << "error: " << PrintSocketIOMessage(message);
}

void BindEvents(const sio::socket::ptr& socket) {
    socket->on_error(&OnError);
    socket->on("add user", sio::socket::event_listener_aux([&](std::string const& name, sio::message::ptr const& data, bool is_ack, sio::message::list &ack_resp) {
        lock.lock();
        BOOST_LOG_TRIVIAL(info) << "add user: " << PrintSocketIOMessage(data);
        lock.unlock();
    }));
    socket->on("new message", sio::socket::event_listener_aux([&](std::string const& name, sio::message::ptr const& data, bool is_ack, sio::message::list &ack_resp) {
        lock.lock();
        BOOST_LOG_TRIVIAL(info) << "new message: " << PrintSocketIOMessage(data);
        lock.unlock();
    }));
    socket->on("typing", sio::socket::event_listener_aux([&](std::string const& name, sio::message::ptr const& data, bool is_ack, sio::message::list &ack_resp) {
        lock.lock();
        BOOST_LOG_TRIVIAL(info) << "typing: " << PrintSocketIOMessage(data);
        lock.unlock();
    }));
    socket->on("stop typing", sio::socket::event_listener_aux([&](std::string const& name, sio::message::ptr const& data, bool is_ack, sio::message::list &ack_resp) {
        lock.lock();
        BOOST_LOG_TRIVIAL(info) << "stop typing: " << PrintSocketIOMessage(data);
        lock.unlock();
    }));
}

tai1235 avatar Sep 08 '21 02:09 tai1235

How to fix the bug?

yihung782-ble avatar Mar 07 '22 08:03 yihung782-ble

same issue In my case, the reason is that server does not send ping message to client and client do not pong for it. when ping_timeout reached, server send a disconnect Control frame with opcode 8 to client. and disconnection occur.

the soultion is keep socket.io server and client same version. if server(js) is version 2.x, client(cpp) version should be 2.x; if server(js) version is 3.x, client(cpp) version should be 3.x;

maybe different version has different processing for ping-pong, in socket.io-swift code we can find a if case for version.rawValue >= 3

private func handlePing(with message: String) { if version.rawValue >= 3 { write("", withType: .pong, withData: []) }

    client?.engineDidReceivePing()
}

badousuan avatar Jul 26 '22 07:07 badousuan