How to write data to TcpSocket from another thread?



  • On the computer work two thread. First, the Tcp server transfers data from the target PC to the UART. The second one checks the buffer for data (polling). UART is very slow so it is impossible to run everything in one thread. Need send data via Tcp Server to the target PC upon arrival of the data to UART, but when calling the write method to the port, the server drops to the records ( socket->write ( data ); ) or even so does not allow writing to the port ( socket->write ( "data" ); ). Where can I find documentation or an example to resolve this issue?

    UART the error happens after calling in the parse method of recording myserver.write():

    void UART_Protokol::ParseCommand()
    {
       MyServer myserver;
    
      if(sp_dataString == "Start") { TransmitData = "ready"; sp_Send(TransmitData); qDebug()<<"Self-test"; }
      if(sp_dataString == "ready") qDebug()<<"Self-test";
    
      if (sp_dataString =="MG1")  myserver.write("MG1");  //After the Debug message is displayed, the application crashes 
      if (sp_dataString =="MG0")  myserver.write("MG0");
      if (sp_dataString =="MG")  qDebug()<<"Calibration...";
    }
    

    Part of the Tcp server here is the method of writing MyServer::write at the very end:

    #include "myserver.h"
    
    
    MyServer::MyServer(){} 
    
    MyServer::~MyServer(){}
    
    
    
    
    void MyServer::startserver()
    
    {
        if (this->listen(QHostAddress::Any,8981))qDebug()<<"Server started";
        else{ qDebug()<<"Error started server";}
    
    }
    
    
    
    void MyServer::incomingConnection(int socketDescriptor ) 
    {
        socket = new QTcpSocket(this);
    
        socket->setSocketDescriptor( socketDescriptor);
    
        connect(socket,SIGNAL(readyRead()),this,SLOT(read())); 
        connect(socket,SIGNAL(disconnected()),this,SLOT(disconect())); 
    
        qDebug()<<socketDescriptor<<"Client connected";
    
        socket->write("Connection");
    
    }
    void MyServer::read()
    {
         UART_Protokol UART;
    
         UART.StartProtokol( false );
    
         arr = socket->readAll();
         data += arr;
    
    
          if ( data == "wu" )UART.sp_Send("wu");
          if ( data == "su" )UART.sp_Send("su");
          if ( data == "au" )UART.sp_Send("au");
          if ( data == "du" )UART.sp_Send("du");
          if ( data == "qu" )UART.sp_Send("qu");
          if ( data == "eu" )UART.sp_Send("eu");
          if ( data == "wd" )UART.sp_Send("wd");
          if ( data == "sd" )UART.sp_Send("sd");
          if ( data == "ad" )UART.sp_Send("ad");
          if ( data == "dd" )UART.sp_Send("dd");
          if ( data == "qd" )UART.sp_Send("qd");
          if ( data == "ed" )UART.sp_Send("ed");
          if (data == "SD1")UART.sp_Send("SD1");
          if (data == "SD0")UART.sp_Send("SD0");
          if (data == "cl")UART.sp_Send("cl");
    
          if( arr[0] == Mask[0]&& arr[1] == Mask[1])
          {
              int length = 0;
    
              QByteArray dt = "tr";
    
              trust[0] =0;
              trust[1] =0;
              trust[2] =0;
    
              length = arr[2];
              trust[0] =arr[3];
              trust[1] =arr[4];
              trust[2] =arr[5];
    
              truster = convert(trust, length - 48);
    
              dt[2] = truster;
    
              UART.sp_Send_integer(dt);
          }
    
          arr.clear(); 
          data = "";
    
    }
    
    void MyServer::disconect()
    
    { 
        socket->deleteLater();
    }
    
    
    void MyServer::write (QByteArray dat)
    {
      
     //An error occurs here
    
     qDebug()<<dat;  // Debug work is fine
    
     socket->write(dat);
    
    // it doesn't work too  socket->write ("MG1");
    
    }
    

    Just in case UART and TcpServer threads are started:

    #include <QCoreApplication>
    #include <myserver.h>
    #include <protokol_obmena_cherez_uart.h>
    #include <QDebug>
    #include <thread>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        UART_Protokol Serial;
    
        Serial.StartProtokol( false );
    
        std::thread serial (&UART_Protokol::Event, Serial);  
    
        MyServer Server;
    
        Server.startserver();
    
        return a.exec();
    }
    

  • Lifetime Qt Champion

    Hi
    Could you not just use signal and slot ?
    So when UART has data it emit signal to MyServer to actually send some reply ?
    But im having hard time to understand the code as you seem to both
    make a UART_Protokol and Myserver in main but at the same time
    also make new one in void MyServer::read() and
    a server in void UART_Protokol::ParseCommand()
    so im not really sure what class should be talking to what class.



  • I've tried using the signal for the recording method but nothing either fail.

    It was necessary to create a new class to inherit Q_OBJECT otherwise the linker does not allow to use WiringPi for work with UART.

    
    class Signals: public QObject
    {
    
     Q_OBJECT
    
    public:
        Signals();
    
    
    public slots:
       void setValue();
    signals:
       void event_uart();
    
    };
    
    
    Signals::Signals(){}
    
    void Signals::setValue()
    {
      emit event_uart();
    }
    
    

    The MyServer::write slot does not work when sending a signal.

    void MyServer::incomingConnection(int socketDescriptor ) 
    {
        socket = new QTcpSocket(this);
    
        Signals ref;
    
        socket->setSocketDescriptor( socketDescriptor );
    
        connect(socket,SIGNAL(readyRead()),this,SLOT(read())); 
    
        connect(socket,SIGNAL(disconnected()),this,SLOT(disconect())); 
    
        connect(&ref,SIGNAL(event_uart()), this,SLOT(write()));  //connected signal with UART 
    
        qDebug()<<socketDescriptor<<"Client connected";
    
        socket->write("Connection");
    
    }
    
    void UART_Protokol::ParseCommand()
    {
    
       Signals ref;
    
      if(sp_dataString == "Start") { TransmitData = "ready"; sp_Send(TransmitData); qDebug()<<"Self-test"; }
      if(sp_dataString == "ready") qDebug()<<"Self-test";
    
      if (sp_dataString =="MG1")  { qDebug()<<"Start calibration..."; ref.setValue(); // send signal       }
      if (sp_dataString =="MG0")  { qDebug()<<"End calibration..."; ref.setValue();                                 }
      if (sp_dataString =="MG")   { qDebug()<<"Calibration...";                                            }
    }
    

  • Lifetime Qt Champion

    Hi
    I wonder about

    void MyServer::incomingConnection(int socketDescriptor ) 
    {
        socket = new QTcpSocket(this);
    
        Signals ref; // this is local object and will be deleted as soon as function ends
    
        socket->setSocketDescriptor( socketDescriptor );
    
        connect(socket,SIGNAL(readyRead()),this,SLOT(read())); 
    
        connect(socket,SIGNAL(disconnected()),this,SLOT(disconect())); 
    
        connect(&ref,SIGNAL(event_uart()), this,SLOT(write()));  //connected signal with UART 
    
        qDebug()<<socketDescriptor<<"Client connected";
    
        socket->write("Connection");
    
    }
    

    Since Signals ref; is gone as soon as function ends, how will it ever emit event_uart()
    once data arrives ?

    i was expecting something like

    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        UART_Protokol Serial;
        Serial.StartProtokol( false );
       std::thread serial (&UART_Protokol::Event, Serial);  
    
        MyServer Server;
       connect(&Serial, UART_Protokol::ServerWrite, &Server, MyServer::write, Qt::QueuedConnection); // or similar
     
        Server.startserver();
    
        return a.exec();
    }
    
    and then in (and other places )
    void UART_Protokol::ParseCommand()
    {
    // MyServer myserver; // why make a new local server when you have one in main ??
    .....
      if (sp_dataString =="MG1")  emit ServerWrite("MG1");  //emit signal to server in main
    .....
    }
    
    


  • I can't use the emit ServerWrite signal because I need UART_Protokol class inherit to the QObject class without this will be error when creating the signal slot. But i cannot inherit this class because the linker throws an error.

    class UART_Protokol
    {
    
     Q_OBJECT //If i inherit QObject to the UART_Protokol: undefined reference to `vtable for UART_Protokol'
    
    //And without Q_OBJECT I can't use signals
    
    signals:
    
      void ServerWrite (QByteArray dat);
    

    Is this how it's gonna work? Can I use a signal from another class?

    QObject::connect (&signal,&Signals::setValue, &Server,&MyServer::write, Qt::QueuedConnection);
    
    

  • Lifetime Qt Champion

    HI
    Cant you just do
    class UART_Protokol : public QObject
    {
    Q_OBJECT
    ...

    ah,
    undefined reference to `vtable for UART_Protokol'

    thats happens often.
    just inherit from QObject
    then clean all of build folder
    and then rebuild all.
    Its a known error coming from not all is recompiled after adding QObject



  • I cleaned up the entire contents of the folder and reassembled everything. Error appeared: "Class contains Q_OBJECT macro but does not inherit from QObject ":

    /#ifndef PROTOKOL_OBMENA_CHEREZ_UART_H
    #define PROTOKOL_OBMENA_CHEREZ_UART_H
    #include <QString>
    #include <thread>
    #include <myserver.h>
    #include <QObject>
    
    class UART_Protokol 
    {
    
     Q_OBJECT
    

    If inherit a class from QObject how in other example, other errors occur:

    #ifndef PROTOKOL_OBMENA_CHEREZ_UART_H
    #define PROTOKOL_OBMENA_CHEREZ_UART_H
    #include <QString>
    #include <thread>
    #include <myserver.h>
    #include <QObject>
    
    class UART_Protokol : public QObject
    {
    
     Q_OBJECT
    

    use of deleted function ‘UART_Protokol::UART_Protokol(const UART_Protokol&)’
    : _M_head_impl(std::forward<_UHead>(__h)) { }

    ‘QObject::QObject(const QObject&)’ is private within this context

    use of deleted function ‘QObject::QObject(const QObject&)’
    class UART_Protokol : public QObject
    ^~~~~~~~~~~~~
    ^
    no matching function for call to ‘std::tuple<std::_Mem_fn<void (UART_Protokol::)()>, UART_Protokol>::tuple(std::_Mem_fn<void (UART_Protokol::)()>, UART_Protokol&)’
    : _M_bound(std::forward<_Tp>(__f), std::forward<_Up>(__args)...)
    ^


  • Lifetime Qt Champion

    Hi,

    That means that you are trying to copy an instance of your object which is not possible with QObject based classes.

    See here for more information.



  • If I inherit the class :

    class UART_Protokol : public QObject
    {
    
        Q_OBJECT
    

    and comment on a thread, everything is going without errors:

    // std::thread serial (&UART_Protokol::Event, Serial); 
    
    // serial.detach();
    
    

    even connecting signal to slot, build is fine:

    QObject::connect (&Serial,&UART_Protokol::ServerWrite, &Server,&MyServer::write, Qt::QueuedConnection);
    

    That's just it I need to check the UART buffer for reading messages.


  • Lifetime Qt Champion

    Did you read the document I linked regarding copying QObject based classes ?



  • Thank you all for your help, the signals really work fine and now i can easily pass the calibration data of the magnetometer! The truth is everything works in one thread with a timer but the delay is not big.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.