在多线程编程中,不能使用QTcpServer的nextPendingConnection函数来获取客户端连接,要继承QTcpServer,重写虚函数incomingConnection来建立新线程,在新线程的run函数中使用new来实例化QTcpSocket,并且使用setSocketDescriptor函数来关联客户端连接。
在线程中使用connect函数关联QTcpSocket信号与槽函数的时候,需要使用Qt::DirectConnection来设置第五个参数,否则在信号到来的时候会报告下面的错误:
//继承自QTcpServer的类:
class MyTcpServer : public QTcpServer
{
Q_OBJECT
public:
MyTcpServer(QObject* parent = 0) :
QTcpServer(parent){};
protected:
void incomingConnection(qintptr handle) override
{
ServerConnectionThread* thread =
new ServerConnectionThread(handle, this);
connect(thread, &ServerConnectionThread::finished,
thread, &ServerConnectionThread::deleteLater);
thread->start();
emit newConnection(thread);
}
signals:
void newConnection(ServerConnectionThread*);
};
//在新建的线程中将QTcpSocket实例与客户端连接关联到一起
void ServerConnectionThread::run()
{
clientSocket = new QTcpSocket();
//由于不能将clientSocket的父指针设成this,因此需要在线程结束的时候做清理工作:
connect(this, &ServerConnectionThread::finished,
clientSocket, &QTcpSocket::deleteLater);
//由于QTcpSocket不能够跨线程操作,因此只能通过传递套接字描述符的方式在子线程中
//设置QTcpSocket与客户端连接的关联。
if (!clientSocket->setSocketDescriptor(clientHandle))
{
emit errorStr(clientSocket->errorString());
return;
}
emit sendClientAddrAndThreadId(this,
clientSocket->peerAddress().toString(),
(qint64)currentThreadId());
connect(clientSocket, &QTcpSocket::readyRead,
this, &ServerConnectionThread::readSocket,
Qt::DirectConnection);
qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
connect(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(sendError(QAbstractSocket::SocketError)));
exec();
}