Qt QTcpServerWork Good But In Linux i have problem....
-
Hello, i don't misunderstand why this code not working on Linux.
- QTcpServer
class CTcpServer : public QTcpServer { //...some code private slots: void incomingConnection(qintptr socketDescriptor); }
void CTcpServer::incomingConnection(qintptr socketDescriptor) { CSessionManager::Instance()>AddTcpSocketConnection(socketDescriptor); }
- Class for handling session(SessionManager).
This class wait few sockets and his next step create thread where this few sockets join for group working..
void CSessionManager::AddTcpSocketConnection(qintptr socketDesctiptor) { CTcpSocket * lpSocket = new CTcpSocket(); if(lpSocket->setSocketDescriptor(socketDesctiptor)) { connect(lpSocket, SIGNAL(BindReady(CTcpSocket*)), this, SLOT(BindReady(CTcpSocket*))); lpSocket->InitSignals(); } else lpSocket->deleteLater(); }
- QTcpSocket - this simple logic for check data when first data transfer on server, if transferred data is ok, this socket move to vector.
class CTcpSocket : public QTcpSocket { Q_OBJECT public: explicit CTcpSocket(QObject * parent = 0); ~CTcpSocket(); bool IsMasterBind(); bool IsSlaveBind(); void InitSignals(); void ReleaseSignals(); //some code private slots: void TcpDataReadyRead(); signals: void BindReady(CTcpSocket *); } void CTcpSocket::InitSignals() { connect(this, SIGNAL(readyRead()), this, SLOT(TcpDataReadyRead())); connect(this, SIGNAL(disconnected()), this, SLOT(deleteLater())); m_bMasterBind = false; m_bSlaveBind = false; } void CTcpSocket::ReleaseSignals() { disconnect(this, SIGNAL(readyRead()), this, SLOT(TcpDataReadyRead())); disconnect(this, SIGNAL(disconnected()), this, SLOT(deleteLater())); } void CTcpSocket::TcpDataReadyRead() { m_buffer += this->readAll(); if(m_buffer == "Master") //For example m_bMasterBind = true; else if(m_buffer == "Slave") //For example m_bSlaveBind = true; //some code for check data if is ok emit BindReady(this); }
so if BindReady return to CSessionManager..
void CSessionManager::BindReady(CTcpSocket * ptr) { qDebug() << "Bind Signal Ready!"; if(ptr->IsMasterBind()) { ptr->ReleaseSignals(); //Yes new data must going in thead... m_sockdesklist.push_back(ptr); } else if(ptr->IsSlaveBind()) { QVector<CTcpSocket*>::iterator it; for(it = m_sockdesklist.begin(); it != m_sockdesklist.end(); it++) { rdt::CTcpSocket * lpMaster = *it; if(lpMaster->IsMasterBind()) { ptr->ReleaseSignals(); //Yes new data going in thead... //Create Thread !! CSessionThread * lpThread = new CSessionThread(lpMaster->socketDescriptor(), ptr->socketDescriptor(), "some arg", this); connect(lpThread, SIGNAL(finished()), lpThread, SLOT(deleteLater())); //Thread Created lpThread->start(); } } }
- CSessionThread for two sockets....
class CSessionThread : public QThread { Q_OBJECT public: explicit CSessionThread(qintptr sockSrc, qintptr sockDst, const QString sessionId, QObject *parent = 0); protected: void run() override; public slots: void SrcReadyRead(); void DstReadyRead(); private: QTcpSocket *socketSrc; QTcpSocket *socketDst; qintptr socketDescriptorSrc; qintptr socketDescriptorDst; } CSessionThread::CSessionThread(qintptr sockSrc, qintptr sockDst, const QString sessionId, QObject *parent) : QThread(parent) { this->socketDescriptorSrc = sockSrc; this->socketDescriptorDst = sockDst; this->m_sessionId = sessionId; if(this->socketDescriptorDst == -1) qDebug() << "Dst socket desk error = -1"; if(this->socketDescriptorSrc == -1) qDebug() << "Src socket desk error = -1"; } void CSessionThread::run() { qDebug() << " Thread started"; socketSrc = new QTcpSocket(); socketDst = new QTcpSocket(); socketSrc->setSocketDescriptor(this->socketDescriptorSrc); socketDst->setSocketDescriptor(this->socketDescriptorDst); if(socketSrc->isValid() && socketDst->isValid()) { connect(socketSrc, SIGNAL(readyRead()), this, SLOT(SrcReadyRead()), Qt::DirectConnection); connect(socketDst, SIGNAL(readyRead()), this, SLOT(DstReadyRead()), Qt::DirectConnection); socketSrc->readAll(); socketDst->readAll(); exec(); socketSrc->abort(); socketSrc->close(); socketDst->abort(); socketDst->close(); } socketSrc->deleteLater(); socketDst->deleteLater(); }
void CSessionThread::SrcReadyRead() { THIS CODE NOT WORK CORRECTLY IN LINUX, BUT IN WINDOWS IS OK socketDst->write(socketSrc->readAll()); } void CSessionThread::DstReadyRead() { THIS CODE NOT WORK CORRECTLY IN LINUX, BUT IN WINDOWS IS OK socketSrc->write(socketDst->readAll()); }
I Can' understand why this code SrcReadyRead() and DstReadyRead() work is good on Windows but on Linux this work withot errors. In Linux OS This code run some iteration...and still block..
void rdt::CSessionThread::SrcReadyRead()
{
socketDst->write(socketSrc->readAll()); //This Code not receive readyRead In Linux...
}void rdt::CSessionThread::DstReadyRead()
{
socketSrc->write(socketDst->readAll()); //This Code not receive readyRead In Linux...
}In Linux, this code is executed several times,
then it will be blocked, SrcReadyRead and DstReadyRead will not receive signals.
If I break the connection,
I will get an error: qsocketnotifier: Invalid socket 20 and type 'Read', disabling.
From here two questions why it does not work in Linux,
and in Windows
it works fine and whether it is possible to monitor two sockets in one thread,
I do not want to create a separate thread for each socket.
My task is to create one thread for two sockets.
And Forward the data between them when the relevant events occur. -
Hello, i don't misunderstand why this code not working on Linux.
- QTcpServer
class CTcpServer : public QTcpServer { //...some code private slots: void incomingConnection(qintptr socketDescriptor); }
void CTcpServer::incomingConnection(qintptr socketDescriptor) { CSessionManager::Instance()>AddTcpSocketConnection(socketDescriptor); }
- Class for handling session(SessionManager).
This class wait few sockets and his next step create thread where this few sockets join for group working..
void CSessionManager::AddTcpSocketConnection(qintptr socketDesctiptor) { CTcpSocket * lpSocket = new CTcpSocket(); if(lpSocket->setSocketDescriptor(socketDesctiptor)) { connect(lpSocket, SIGNAL(BindReady(CTcpSocket*)), this, SLOT(BindReady(CTcpSocket*))); lpSocket->InitSignals(); } else lpSocket->deleteLater(); }
- QTcpSocket - this simple logic for check data when first data transfer on server, if transferred data is ok, this socket move to vector.
class CTcpSocket : public QTcpSocket { Q_OBJECT public: explicit CTcpSocket(QObject * parent = 0); ~CTcpSocket(); bool IsMasterBind(); bool IsSlaveBind(); void InitSignals(); void ReleaseSignals(); //some code private slots: void TcpDataReadyRead(); signals: void BindReady(CTcpSocket *); } void CTcpSocket::InitSignals() { connect(this, SIGNAL(readyRead()), this, SLOT(TcpDataReadyRead())); connect(this, SIGNAL(disconnected()), this, SLOT(deleteLater())); m_bMasterBind = false; m_bSlaveBind = false; } void CTcpSocket::ReleaseSignals() { disconnect(this, SIGNAL(readyRead()), this, SLOT(TcpDataReadyRead())); disconnect(this, SIGNAL(disconnected()), this, SLOT(deleteLater())); } void CTcpSocket::TcpDataReadyRead() { m_buffer += this->readAll(); if(m_buffer == "Master") //For example m_bMasterBind = true; else if(m_buffer == "Slave") //For example m_bSlaveBind = true; //some code for check data if is ok emit BindReady(this); }
so if BindReady return to CSessionManager..
void CSessionManager::BindReady(CTcpSocket * ptr) { qDebug() << "Bind Signal Ready!"; if(ptr->IsMasterBind()) { ptr->ReleaseSignals(); //Yes new data must going in thead... m_sockdesklist.push_back(ptr); } else if(ptr->IsSlaveBind()) { QVector<CTcpSocket*>::iterator it; for(it = m_sockdesklist.begin(); it != m_sockdesklist.end(); it++) { rdt::CTcpSocket * lpMaster = *it; if(lpMaster->IsMasterBind()) { ptr->ReleaseSignals(); //Yes new data going in thead... //Create Thread !! CSessionThread * lpThread = new CSessionThread(lpMaster->socketDescriptor(), ptr->socketDescriptor(), "some arg", this); connect(lpThread, SIGNAL(finished()), lpThread, SLOT(deleteLater())); //Thread Created lpThread->start(); } } }
- CSessionThread for two sockets....
class CSessionThread : public QThread { Q_OBJECT public: explicit CSessionThread(qintptr sockSrc, qintptr sockDst, const QString sessionId, QObject *parent = 0); protected: void run() override; public slots: void SrcReadyRead(); void DstReadyRead(); private: QTcpSocket *socketSrc; QTcpSocket *socketDst; qintptr socketDescriptorSrc; qintptr socketDescriptorDst; } CSessionThread::CSessionThread(qintptr sockSrc, qintptr sockDst, const QString sessionId, QObject *parent) : QThread(parent) { this->socketDescriptorSrc = sockSrc; this->socketDescriptorDst = sockDst; this->m_sessionId = sessionId; if(this->socketDescriptorDst == -1) qDebug() << "Dst socket desk error = -1"; if(this->socketDescriptorSrc == -1) qDebug() << "Src socket desk error = -1"; } void CSessionThread::run() { qDebug() << " Thread started"; socketSrc = new QTcpSocket(); socketDst = new QTcpSocket(); socketSrc->setSocketDescriptor(this->socketDescriptorSrc); socketDst->setSocketDescriptor(this->socketDescriptorDst); if(socketSrc->isValid() && socketDst->isValid()) { connect(socketSrc, SIGNAL(readyRead()), this, SLOT(SrcReadyRead()), Qt::DirectConnection); connect(socketDst, SIGNAL(readyRead()), this, SLOT(DstReadyRead()), Qt::DirectConnection); socketSrc->readAll(); socketDst->readAll(); exec(); socketSrc->abort(); socketSrc->close(); socketDst->abort(); socketDst->close(); } socketSrc->deleteLater(); socketDst->deleteLater(); }
void CSessionThread::SrcReadyRead() { THIS CODE NOT WORK CORRECTLY IN LINUX, BUT IN WINDOWS IS OK socketDst->write(socketSrc->readAll()); } void CSessionThread::DstReadyRead() { THIS CODE NOT WORK CORRECTLY IN LINUX, BUT IN WINDOWS IS OK socketSrc->write(socketDst->readAll()); }
I Can' understand why this code SrcReadyRead() and DstReadyRead() work is good on Windows but on Linux this work withot errors. In Linux OS This code run some iteration...and still block..
void rdt::CSessionThread::SrcReadyRead()
{
socketDst->write(socketSrc->readAll()); //This Code not receive readyRead In Linux...
}void rdt::CSessionThread::DstReadyRead()
{
socketSrc->write(socketDst->readAll()); //This Code not receive readyRead In Linux...
}In Linux, this code is executed several times,
then it will be blocked, SrcReadyRead and DstReadyRead will not receive signals.
If I break the connection,
I will get an error: qsocketnotifier: Invalid socket 20 and type 'Read', disabling.
From here two questions why it does not work in Linux,
and in Windows
it works fine and whether it is possible to monitor two sockets in one thread,
I do not want to create a separate thread for each socket.
My task is to create one thread for two sockets.
And Forward the data between them when the relevant events occur.In a wild guess I assume that the socket buffering in linux is less favorable with the write readAll combination in *ReadyRead routines. Probably you have even high throughput on those tcp sockets. However also low throughput there might be situations where the readyRead will be missed. All dependends on the actual sockjet handling in the OS. I would not even bother to dig deeper.
Personally I think the combination of write with readAll you do in your code is dangerous and I would avoid in all non-file operations. My suggestion is a small while loop using bytesAvailable and reading chunks.More along those lines
while ( socketDst->bytesAvailable() ) { char line[1024]; qint64 avail = socketDst->bytesAvailable(); qint64 len = avail < 1024 ? avail : 1024; socketDst->readLine ( char, len ); }
Also some precautions to break when too much data is in buffer would be good.
Note: source above is brain to keyboard. Check it properly.
-
thx koahnig
while ( socketDst->bytesAvailable() ) { char line[1024]; qint64 avail = socketDst->bytesAvailable(); qint64 len = avail < 1024 ? avail : 1024; socketDst->readLine ( char, len ); }
I replaced with what you wrote, but this is still not a solution. I suspect that on Linux, you can not use two sockets in the same thread, although I may be wrong. Such a feeling that when events occur from one socket, another ceases to work out correctly. I think that it will be necessary to change the architecture of the application, if no solution is found for this problem ...
-
thx koahnig
while ( socketDst->bytesAvailable() ) { char line[1024]; qint64 avail = socketDst->bytesAvailable(); qint64 len = avail < 1024 ? avail : 1024; socketDst->readLine ( char, len ); }
I replaced with what you wrote, but this is still not a solution. I suspect that on Linux, you can not use two sockets in the same thread, although I may be wrong. Such a feeling that when events occur from one socket, another ceases to work out correctly. I think that it will be necessary to change the architecture of the application, if no solution is found for this problem ...
Sorry, the snippet above is missing the sending part, but you probably have figured that part.
I have used on windows as well as on linux such implementations with no apparent problems. The comms are basically packets of to about 4kB per second.
However, as already noted above it is wise to take care of stopping the loop in case a large amount of data is in the buffer and needs to read and send again. Therefore, it is important for you to think the data quantities you are expecting.Breaking out of the loop after reading a certain amount might be smart for giving other parts the application a chance to get executed. However, you have make sure that you are not forgetting the remainder of the bytes, because readyRead will triggered only when you are not in a connected slot and new data is available.