Hello, I am writing a client-server application. As a result, for each connection I want to take a stream from QThreadPool ... this is still a draft, so the code is appropriate, but the server only sends data to the client, but receives nothing from it, although it should:

server.h:

#include <QTcpServer> #include <QAbstractSocket> #include <QTcpSocket> #include <QThreadPool> #include "tcpconnection.h" void log_(const QString& msg); class TcpServer_impl final : public QTcpServer { Q_OBJECT public: explicit TcpServer_impl(QObject* parent = nullptr); ~TcpServer_impl(); Q_SIGNALS: void createConnection(quintptr descriptor); protected: void incomingConnection(qintptr descriptor) override final; }; class CServer final : public QObject { Q_OBJECT public: CServer(std::size_t port, QObject *parent = nullptr); ~CServer(); void listen(); void stop(); void reload(); //void waitClients(); void setMaxThreads(size_t n); std::size_t getPort() { return m_Port; } enum STATE { STATE_INIT = 0, STATE_STOPPED, STATE_STARTED, STATE_RELOADED }; public Q_SLOTS: // обработчик входного соединения void connection_handler(quintptr descriptor); private: std::size_t m_Port = 0; STATE m_State; // QHash<int, QTcpSocket*> m_TcpClients; // Qhash<int, QLocalSocket*> m_USockClients; QHash<int, IConnection*> m_Connections; TcpServer_impl* m_Serv; QThreadPool* m_Pool; }; 

server.cpp:

 #include "server.h" void log_(const QString &msg) { qDebug() << msg; } TcpServer_impl::TcpServer_impl(QObject *parent) : QTcpServer(parent) { } TcpServer_impl::~TcpServer_impl() { } void TcpServer_impl::incomingConnection(qintptr descriptor) { emit createConnection(descriptor); } CServer::CServer(std::size_t port, QObject* parent) : QObject(), m_Port(port), m_Serv(new TcpServer_impl(this)), m_State(STATE_INIT), m_Pool(new QThreadPool(this)) { connect(m_Serv, &TcpServer_impl::createConnection, this, &CServer::connection_handler); } void CServer::setMaxThreads(std::size_t n) { m_Pool->setMaxThreadCount(n); } CServer::~CServer() { m_Serv->close(); } void CServer::listen() { if(m_Serv->listen(QHostAddress::Any, m_Port)) { log_("server is started"); m_State = STATE_STARTED; } else { log_("Server: not started!"); //_Exit(1); } } //void CServer::waitClients() { // //ждем минуту, если нет соединений то заново // while(!m_Serv->waitForNewConnection(60000)) // { // int stop = 0; // int stop1 = 0; // } //} void CServer::connection_handler(quintptr descriptor) { if(m_State == STATE_STARTED) { IConnection* c = new CTcpConnection(descriptor, this); c->setAutoDelete(true); QThreadPool::globalInstance()->start(c); //m_Pool->start(c); } } void CServer::stop() { } void CServer::reload() { } 

connection.h:

 #include <QThreadPool> #include <QTcpSocket> #include <QRunnable> class IConnection : public QObject, public QRunnable{ Q_OBJECT public: IConnection(QObject* parent = nullptr); virtual ~IConnection(); protected: void run() = 0; }; class CTcpConnection : public IConnection { Q_OBJECT public: explicit CTcpConnection(qintptr _descriptor); CTcpConnection(qintptr _descriptor, QObject* parent); ~CTcpConnection(); public Q_SLOTS: void onRead(); void onDisconnect(); void onWrite(const QString& data); protected: void run(); private: //QTcpSocket m_Sock; qintptr m_Descriptor; }; 

connection.cpp:

 #include "connection.h" IConnection::IConnection(QObject *parent) : QObject(parent) { } IConnection::~IConnection() { } CTcpConnection::CTcpConnection(qintptr _descriptor) : IConnection(), m_Descriptor(_descriptor) { } CTcpConnection::CTcpConnection(qintptr _descriptor, QObject *parent) : IConnection(parent), m_Descriptor(_descriptor) { } CTcpConnection::~CTcpConnection() { //m_Sock.close(); } void CTcpConnection::onRead() { } void CTcpConnection::onWrite(const QString &data) { } void CTcpConnection::onDisconnect() { // m_Sock.close(); } void CTcpConnection::run() { QTcpSocket m_Sock; //connect(&m_Sock, &QTcpSocket::readyRead, this, &CTcpConnection::onRead, Qt::DirectConnection); connect(&m_Sock, &QTcpSocket::readyRead, this, [&m_Sock]{ std::cout << m_Sock.readAll().toStdString(); }, Qt::DirectConnection); connect(&m_Sock, &QTcpSocket::disconnected, this, &CTcpConnection::onDisconnect, Qt::DirectConnection); m_Sock.setSocketDescriptor(m_Descriptor); //этот блок ничего не принимает //while(m_Sock.bytesAvailable()>0) // { // QByteArray array = m_Sock.readAll(); // std::cout<<array.toStdString()<<std::endl; // m_Sock.write(array); // } m_Sock.write("From server: hello world"); m_Sock.flush(); } 

client.cpp:

 #include <QCoreApplication> #include <QTcpSocket> #include <QHostAddress> #include <QDataStream> #include <QObject> #include <QThread> #include <iostream> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTcpSocket *client = new QTcpSocket; QObject::connect(client, &QTcpSocket::connected, client, []{ std::cout<<"connected!!!\n"; }); QObject::connect(client, &QTcpSocket::disconnected, client, &QTcpSocket::deleteLater); QObject::connect(client, &QTcpSocket::readyRead, [&client]{ QByteArray arr = client->readAll(); std::cout<< arr.toStdString() << std::endl; }); client->connectToHost(QHostAddress::LocalHost, 1200); client->waitForConnected(); if (client->state() != QAbstractSocket::ConnectedState ) { qDebug() << Q_FUNC_INFO << " can't connect to host"; delete client; } QByteArray block; // QDataStream out(&block, QIODevice::WriteOnly); // out.setVersion(QDataStream::Qt_5_5); // out << QString("Hello, Server"); // out.device()->seek(0); // client->write(block); client->write("Hello, Server"); return a.exec(); } 

As a result, the client sends the data, and the server sends it the hello world, but accepts nothing from the client, i.e. Signal readyRead not emit ... tell me what the problem

update: added two fields to CTcpConnection: QTcpSocket * m_Sock; QEventLoop * m_Loop; and changed the run and onRead methods:

 void CTcpConnection::onRead() { std::cout << m_Sock->readAll().toStdString() << " " << QThread::currentThreadId(); m_Sock->write("hello from server"); } void CTcpConnection::run() { m_Loop = new QEventLoop(); m_Sock = new QTcpSocket(); //QTcpSocket m_Sock; connect(m_Sock, &QTcpSocket::readyRead, this, &CTcpConnection::onRead, Qt::DirectConnection); connect(m_Sock, &QTcpSocket::disconnected, this, &CTcpConnection::onDisconnect, Qt::DirectConnection); m_Sock->setSocketDescriptor(m_Descriptor); m_Loop->exec(); delete m_Sock; delete m_Loop; } 

now we go to the onRead method, but nothing is output, but the client accepts hello from server ... what's the catch?

update: set the following to the onRead method:

 qDebug << m_Sock->readAll().toStdString() << " " << QThread::currentThreadId(); 

and everything became output ... delivered CTcpConnect to the destructor ...

 delete m_Sock; delete m_Loop; 

and I do not know how correct the decision is at all, that some kind of left eventloop is created in the run method ...

  • You create a client socket on the server side as a local variable "QTcpSocket m_Sock;" After exiting the block, the variable is deleted and the connection is closed. To receive messages from clients, the connection for each of them must be alive and open. Check out this sample chat implementation doc.qt.io/qt-5/qtnetwork-network-chat-example.html - goldstar_labs
  • @goldstar_labs, in that example there is no such thing as a “stream to connect”, ibid broadcast udp in general ... if you make the m_Sock socket a field of a class and not a temporary variable (as I originally wanted), the error "Cannot create children crashes" for a parent that is in a different thread ", so I don’t know what to do ... - xperious
  • Yes, it’s not so easy with QT threads :). You need to change the approach to creating connections on the server side. Do not immediately create a QRunnable task, but create just an object that will create a socket inside itself and create a task, so ownership semantics will be good and tasks will spin in their threads. in more detail here (with an example) bogotobogo.com/Qt/Qt5_Asynchronous_QTcpServer_QThreadPool.php - goldstar_labs
  • @goldstar_labs, updated a little ... - xperious
  • PS gossip about ownership semantics in QT, QT :: QueuedConnection and QT :: DirectConnection, how the signals and slots mechanism works, QT has excellent documentation, and the Internet is full of examples. - goldstar_labs

0