QTcpSocket signal slot in multithread

Viewed 83

I am trying to write a multithreaded server for my application. And I ran into the problem of sending the image to the clients at the same time. I decided to write a singleton class that will trigger a signal on which a frame will come to the sockets and be sent to the client. But when I write connect() it doesn't work or it throws an error "Unable to create an object in another thread". I have tried moveToThread(). Tried Qt::QueuedConnection, it didn't solve the problem. If you can suggest how to simultaneously send a picture by clients via QTcpSocket without broadcast or how to call a slot in QTcpSocket - that would be cool.

I apologize if the code is incomprehensible in some places, I have already tried to solve this problem in different ways and did not always clean non-working options.

OK. First we create the mainwindow in its constructor, we start the datasender server. In IncomingConnection we get the socket handle and pass it to the handler which is inherited from QThread. At the moment I'm trying to write connect () here, earlier I also tried to register a connection inside the socket itself. Next, we start the socket itself and it really successfully connects to the server. By pressing a keyboard key, the emittera signal is called, which, in theory, should trigger slots in sockets and pass cv::Mat or QPixmap to them.

emitter.cpp

    #include "emitter.h"

emitter* emitter::em= nullptr;

emitter::emitter(QObject *parent):
    QObject(parent)
{

}

void emitter::startEmit()
{
    emit testEmit();
}

emitter *emitter::getInstance()
{
    if(em == nullptr){
        em = new emitter();
    }
    return em;
}

server.h

#include "datasender.h"




DataSender::DataSender(QObject *parent) :
    QTcpServer(parent)
{
}

void DataSender::startServer()
{
    if(this->listen(QHostAddress::Any, 8080))
    {
        qDebug() << "Server started";
    }
    else
    {
        qDebug() << "Server did not start!";
    }
}

void DataSender::incomingConnection(qintptr handle)
{

    SocketHandler *task = new SocketHandler(this);
    connect(task, &QThread::finished, task, &QThread::deleteLater);
    task->socketDescriptor = handle;

    task->start();
    qDebug() << "pool started";
}

sockethandler.cpp

#include "sockethandler.h"


SocketHandler::SocketHandler(QObject *parent):
    QThread(parent)
{

}



void SocketHandler::run()
{
    socket = new MySocket();
    socket->setDescriptor(socketDescriptor);
    connect(emitter::getInstance(), &emitter::testEmit, socket, &MySocket::NewData , Qt::QueuedConnection );

    socket->EventLoop();
    exec();
}

mysocket.cpp

#include "mysocket.h"

MySocket::MySocket(QObject *parent) :
    QObject(parent)
{
    qDebug() << "MySocket";



    connect(&socket, &QTcpSocket::disconnected ,
            this, &MySocket::disconnected);
    connect(&socket,  &QTcpSocket::connected,
            this, &MySocket::connected);
    connect(&socket,  &QTcpSocket::readyRead,
            this, &MySocket::readyRead);
    connect(&socket,  &QTcpSocket::bytesWritten,
            this, &MySocket::bytesWritten);
}

void MySocket::setDescriptor(qintptr desk)
{
    socket.setSocketDescriptor(desk);
    Work = true;
}

void MySocket::connected()
{

}

void MySocket::disconnected()
{
    Work = false;
}

void MySocket::readyRead()
{

}

void MySocket::bytesWritten(qint64 bytes)
{
    qDebug() << "bytes written: " << bytes;
}

void MySocket::EventLoop()
{
    if(socket.socketDescriptor()){
        while(Work){
            socket.waitForBytesWritten(500);
        }
    }
}

void MySocket::NewData()
{
    qDebug() << "newData";
    socket.write("Test");
}

mainwindow.cpp

#include "mainwindow.h"
#include "./ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    em = emitter::getInstance();
    datasender.startServer();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::keyPressEvent(QKeyEvent *event)
{
    gogogo();
}

void MainWindow::gogogo()
{
    qDebug() << "Work";
    em->startEmit();

}
1 Answers

In your SocketHandler::run(), you are creating an object (the socket).

It's probably safe to assume SocketHandler is a QRunnable according to this methods name, and is therefore called in a threaded fashion by your QThreadPool

Your error says you are creating an object in a thread, well, from what I can see, it's your socket.

To get around this, make the socket a member of your SocketHandler class

Edit:

There's one other thing that got my attention: you're inheriting QThread.

This usually breaks things or causes weird behavior. It's safer if you can do without inheriting it as you can't break it if you don't touch it, it might be what's causing the problem.

To add functionality to it without inheriting it, I would wrap it into some class that would implement whatever it is that's required.

Related