我试图通过使用QRunnable和QThreadPool而不是每个连接1个线程,以可扩展的方式使用Qt 5.2编写tcp服务器。
我遇到的问题是,在QRunnable::run中创建的套接字在我创建它并设置它的套接字描述符时具有连接状态,但是调用readAll()响应readyRead信号产生空缓冲区,即使我知道我发送了一些数据。
我尝试将套接字从主线程传递到QRunnable的两种方式是:
1)从QTcpServer::nextPendingConnection获取QTcpSocket,并将socket描述符传递给QRunnable。
2)覆盖QTcpServer::incomingConnection并从那里获得套接字描述符并将其传递给QRunnable。
两者都给出相同的结果,接收到套接字readyread信号,但readAll返回空缓冲区。
感谢RobbieE纠正了我的误解。下面是一个如何使用QRunnables和QThreadpool编写Tcp Server的工作示例。我是Qt的新手,所以欢迎任何批评/改进/讨论。这段代码并不打算达到生产质量,只是一个简单的示例,说明如何编写一个可扩展的tcp服务器。
#include <QCoreApplication>
#include "server.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Server server;
if(server.Start())
{
qDebug() << "Server started" ;
}
else
{
qDebug() << "Server Failed to start" ;
}
return a.exec();
}
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
class Server : public QObject
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
bool Start();
signals:
public slots:
void onNewConnection();
private:
QTcpServer* m_pServer;
};
#endif // SERVER_H
server.cpp
#include "server.h"
#include "myrunnable.h"
#include <QThreadPool>
Server::Server(QObject *parent) :
QObject(parent)
{
m_pServer = new QTcpServer(this);
}
bool Server::Start()
{
bool bOK = true;
if(m_pServer->listen(QHostAddress::Any,1971))
{
connect(m_pServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
}
else
{
qDebug() << "Failed to start listening";
bOK = false;
}
return bOK;
}
void Server::onNewConnection()
{
qDebug() << "onNewConnection";
QTcpSocket* pSocket = m_pServer->nextPendingConnection();
qintptr descriptor = pSocket->socketDescriptor();
MyRunnable* pRunnable = new MyRunnable();
pRunnable->setAutoDelete(true);
pRunnable->setDescriptor(descriptor);
QThreadPool::globalInstance()->start(pRunnable);
}
myrunnable.h
#ifndef MYRUNNABLE_H
#define MYRUNNABLE_H
#include <QObject>
#include <QTcpSocket>
#include <QRunnable>
#include <QEventLoop>
class MyRunnable : public QObject, public QRunnable
{
Q_OBJECT
public:
explicit MyRunnable(QObject *parent = 0);
~MyRunnable();
void run();
void setDescriptor(qintptr descriptor);
signals:
public slots:
void onConnected();
void onDisconnect();
void onReadyRead();
private:
qintptr m_socketDecriptor;
QTcpSocket* m_pSocket;
QEventLoop* m_pEventLoop;
};
#endif // MYRUNNABLE_H
myrunnable.cpp
#include "myrunnable.h"
#include <QEventLoop>
#include <QThread>
MyRunnable::MyRunnable(QObject *parent) :
QObject(parent),m_pSocket(0)
{
}
MyRunnable::~MyRunnable()
{
qDebug() << "MyRunnable destructor called";
}
void MyRunnable::run()
{
m_pEventLoop = new QEventLoop();
m_pSocket = new QTcpSocket();
if(m_pSocket->setSocketDescriptor(m_socketDecriptor))
{
connect(m_pSocket,SIGNAL(connected()),this,SLOT(onConnected()),Qt::QueuedConnection);
connect(m_pSocket,SIGNAL(disconnected()),this,SLOT(onDisconnect()),Qt::QueuedConnection);
connect(m_pSocket,SIGNAL(readyRead()),this,SLOT(onReadyRead()),Qt::QueuedConnection);
}
m_pEventLoop->exec();
delete m_pSocket;
delete m_pEventLoop;
}
void MyRunnable::setDescriptor(qintptr descriptor)
{
m_socketDecriptor = descriptor;
}
void MyRunnable::onConnected()
{
qDebug() << "Connected";
}
void MyRunnable::onDisconnect()
{
qDebug() << "Disconnected";
//m_pEventLoop->disconnect();
m_pEventLoop->exit();
}
void MyRunnable::onReadyRead()
{
qDebug() << m_pSocket->readAll();
for(int i=0;i<4;i++)
{
qDebug() << "Sleeping for 5 seconds to simulate work being done.rn";
QThread::sleep(5);
qDebug() << "...rn";
}
//qDebug() << "OnReadReady";
}