首页 > 解决方案 > Socket.io Client C++, get array from socket.on

问题描述

I'm building an implementation of Socket.io client for C++ able to manage an array of objects at same time, I have a Node.JS server configured like this to send an Array of objects in JSON Format

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var numeroconectados = 0;
var booleano = 0;
var valormotor = 0,
  valorled = 0,
  valorpiston = 0,
  valorultrasonico = 0;
app.get('/', function(req, res) {
  res.sendFile(__dirname + '/public/index.html');
});

io.on('connection', function(socket) {
  numeroconectados += 1;

  socket.emit('inicializar', {
    'led': valorled,
    'piston': valorpiston,
    'motor': valormotor,
    'ultrasonico': valorultrasonico
  });
  console.log("<<Usuario conectado>> Usuarios en linea: " + numeroconectados);
  socket.on('disconnect', function() {
    numeroconectados -= 1;
    console.log('<<Usuario desconectado>> Usuarios en linea: ' + numeroconectados);
  });

  socket.on("datos", function(data) {
    var sizedatos = data.length;
    console.log(sizedatos);
    for (i = 0; i < sizedatos; i++) {
      console.log("Nombre: " + data[i].nombre + " Tipo: " + data[i].tipo +
        " Valor: " + data[i].valor);
        if(data[i].tipo == 'motor') valormotor = data[i].valor;
        if(data[i].tipo == 'led') valormotor = data[i].valor;
        if(data[i].tipo == 'ultrasonico') valormotor = data[i].valor;
        if(data[i].tipo == 'piston') valormotor = data[i].valor;
    }
    socket.broadcast.emit('datos', data); //Envia a todos los clientes

  });
  /*socket.on('motor', function(msg) {
    console.log('motor ' + msg);
    valormotor = msg;
    socket.broadcast.emit('motor', msg);
  });
  socket.on('led', function(msg) {
    valorled = msg;
    console.log('led ' + msg);
    socket.broadcast.emit('led', msg);
  });
  socket.on('ultrasonico', function(msg) {
    valorultrasonico = msg;
    console.log('ultrasonico ' + msg);
    socket.broadcast.emit('ultrasonico', msg);
  });
  socket.on('piston', function(msg) {
    valorpiston = msg;
    console.log('piston ' + msg);
    socket.broadcast.emit('piston', msg);
  });*/
});

http.listen(3000, function() {
  console.log('listening on *:3000');
});

I have an object to store data, to improve responsiveness of the system send a vector of objects when some of them had changed. In my C++ program I receive the result array of objects in JSON, for that I have the code

#include "sio_client.h"                 //Librería de Sockets io

#include <functional>                   //Librerías estándar
#include <iostream>
#include <thread>                       //Librerías de Multriprocesamiento
#include <mutex>
#include <condition_variable>
#include <string>                       //Librerías de cadena de caracteres
#include <sstream>

#define HIGHLIGHT(__O__) std::cout<<"\e[1;31m"<<__O__<<"\e[0m"<<std::endl   //Colorear las funciones
#define EM(__O__) std::cout<<"\e[1;30;1m"<<__O__<<"\e[0m"<<std::endl

using namespace sio; //Workspace de Sockets.io
using namespace std; //Workspace de std
std::mutex _lock; //Workspace de multithreading

std::condition_variable_any _cond;
bool connect_finish = false;

/*
 *  Clase para conectar el listener, para aguardar por eventos
 */
class connection_listener {
    sio::client &handler;

public:

    connection_listener(sio::client& h) :
    handler(h) {
    }

    void on_connected() {
        _lock.lock();
        _cond.notify_all();
        connect_finish = true;
        _lock.unlock();
        std::cout << "Servidor conectado correctamente" << std::endl;
    }

    void on_close(client::close_reason const& reason) {
        std::cout << "sio closed " << std::endl;
        exit(0);
    }

    void on_fail() {
        std::cout << "sio failed " << std::endl;
        exit(0);
    }
};

socket::ptr current_socket; //Api de socket
string mensaje;

void eventos() {
    std::cout << "Inicio de recepcion de datos" << std::endl;
    std::vector<std::shared_ptr < message>> hola;
    current_socket->on("datos", sio::socket::event_listener_aux([&](string
            const& name, message::ptr const& data, bool isAck, message::list & ack_resp) {
        _lock.lock(); //Bloquear la ejecucion hasta realizar una opcion
        hola = data -> get_vector();
        for (int i = 0; i < hola.size(); i++) {
            std::cout << hola.at(i)->get_map()["tipo"]->get_string() << std::endl;
                    std::cout << hola.at(i)->get_map()["nombre"]->get_string() << std::endl;
                    std::cout << hola.at(i)->get_map()["tipo"]->get_string() << std::endl;
                    std::cout << hola.at(i)->get_map()["valor"]->get_string() << std::endl;
        }
        _lock.unlock(); //Desbloquear la ejecucion para seguir con el programa
    }));
}

//Separar string con delimitador

std::vector<std::string> split(std::string strToSplit, char delimeter) {
    std::stringstream ss(strToSplit);
    std::string item;
    std::vector<std::string> splittedStrings;
    while (std::getline(ss, item, delimeter)) {
        splittedStrings.push_back(item);
    }
    return splittedStrings;
}

int main(int argc, const char* args[]) {
    sio::client h; //Creación de un nuevo cliente de Sockets.io
    connection_listener l(h); //Añado al cliente un listener para obtener eventos
    h.set_open_listener(std::bind(&connection_listener::on_connected, &l));
    h.set_close_listener(std::bind(&connection_listener::on_close, &l, std::placeholders::_1));
    h.set_fail_listener(std::bind(&connection_listener::on_fail, &l));
    h.connect("http://127.0.0.1:3000"); //Conexión  al servidor Web

    _lock.lock();
    if (!connect_finish) {
        _cond.wait(_lock);
    }
    _lock.unlock();
    current_socket = h.socket(); //Socket para inicio de dato

    //Separar string
    std::vector<std::string> cadenaseparada;

    int numeroentrada = 0;
    string identificador;
    int opcion = 20;
    eventos(); //mandar a llamar una vez, obligatorio
    for (std::string line; std::getline(std::cin, line);) {
        if (line.length() > 0) {
            if (line == "$exit") {
                std::cout << "Salir" << std::endl;
                break;
            } else if (line.length() > 4 && line.length() < 15) {
                cadenaseparada = split(line, ',');
                identificador = cadenaseparada[0];
                mensaje = cadenaseparada[1];
                current_socket->emit(identificador, mensaje);
                _lock.lock();
                std::cout << "Identificador: " << identificador << std::endl << "Mensaje: " << mensaje << std::endl;
                _lock.unlock();
            } else {
                std::cout << "Evento desconocido" << std::endl;
            }
        }
    }
    h.close(); //Cerrar servidor
    return 0;
}

I convert the message::ptr const& data received from current_socket -> on method to std::vector with the method hola = data -> get_vector(); (hola is a std::vector<std::shared_ptr < message>>), but when I want to access the array I get a SIGSEGV error. I wonder if I defined a bad structure for std::vector> hola, any help is aprecciated, thanks

标签: c++vectorwebsocketsocket.iosegmentation-fault

解决方案


Put the definition of hola vector into lambda.

    _lock.lock(); //Bloquear la ejecucion hasta realizar una opcion
    std::vector<std::shared_ptr < message>> hola = data -> get_vector();

Now, in eventos function you create lambda which captures all local variables by reference ( [&] ), so your lambda holds reference to hola vector. hola vector is destroyed when eventos function terminates. You get segmentation fault because your lambda is called outside eventos function, and you try to assign data -> get_vector(); vector to hola object which doesn't exist.


推荐阅读