我试图通过使用QRunnable和QThreadPool而不是每个连接1个线程,以可扩展的方式使用Qt 5.2编写tcp服务器。
我遇到的问题是,在我创建并设置其套接字描述符时,在QRunnable :: run中创建的套接字具有连接状态,但是即使对readyRead信号进行响应,调用readAll()也会产生一个空缓冲区,即使我知道我发送了一些数据。
我尝试将套接字从主线程传递到QRunnable的两种方法是:
1)从QTcpServer :: nextPendingConnection获取QTcpSocket并将套接字描述符传递给QRunnable。
2)重写QTcpServer :: incomingConnection并从那里获取套接字描述符,并将其传递给QRunnable。
两者都给出相同的结果,接收到套接字readyread信号,但readAll返回一个空缓冲区。
任何帮助将不胜感激。
最佳答案
感谢RobbieE纠正了我的误会。这是一个如何编写使用QRunnables和QThreadpool的Tcp服务器的工作示例。我是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();
}
服务器
#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.\r\n";
QThread::sleep(5);
qDebug() << "...\r\n";
}
//qDebug() << "OnReadReady";
}