从文档了解到如果要实现多线程,必须重新实现void incomingConnection(qintptr socketDescriptor),因为默认的会把监听到的套接字创建后挂起,每次只通知一个连接,想要多线程继承QTcpServer后重新实现
//TcpServer.h #pragma once #include <QTcpServer> #include <qsemaphore.h> #include <QMap> class TcpThread; class TcpServer : public QTcpServer { Q_OBJECT public: TcpServer(QObject* parent = nullptr); ~TcpServer(); //退出TCP客户端线程 void closeTcpThread(); //设置是否打开注册 void setOpen(bool mode); //返回Tcp线程数量 int readTcpNum(); //设置关闭模式 void setCloseMode(bool mode); private: bool open; QMap<qintptr, TcpThread*> tcpThread; int connectionNum; //连接数 QSemaphore *seamphore; //线程锁 int sqlNum; //保存数据库连接数 bool closeMode; //是否关闭 protected: void incomingConnection(qintptr socketDescriptor); private slots: //读取消息 void readMessage(const QString &str); //读取刷新数据库信息 void readSelectSql(); //关闭连接 void closeConnection(qintptr socket); signals: //退出线程 void quitThread(); //显示消息 void showMessage(const QString &str); //刷新数据库 void selectSql(); //关闭完成 void closeFinished(); };
//TcpServer.cpp #include "TcpServer.h" #include "TcpThread.h" #include <qdebug.h> TcpServer::TcpServer(QObject *parent) : QTcpServer(parent) { connectionNum = 0; seamphore = new QSemaphore; seamphore->release(); qRegisterMetaType<qintptr>("qintptr"); //注册自定义信号类型 sqlNum = 0; open = false; closeMode = false; } TcpServer::~TcpServer() { } //退出TCP客户端线程 void TcpServer::closeTcpThread() { closeMode = true; if (!tcpThread.isEmpty()) { emit quitThread(); } else { emit closeFinished(); } } //设置是否打开注册 void TcpServer::setOpen(bool mode) { open = mode; } //返回Tcp线程数量 int TcpServer::readTcpNum() { return tcpThread.size(); } //设置关闭模式 void TcpServer::setCloseMode(bool mode) { closeMode = mode; } void TcpServer::incomingConnection(qintptr socketDescriptor) { seamphore->acquire(); //防止并发 锁住 tcpThread[socketDescriptor] = new TcpThread(sqlNum, socketDescriptor, this); tcpThread[socketDescriptor]->setOpen(open); connect(this, &TcpServer::quitThread, tcpThread[socketDescriptor], &TcpThread::closeTcpSocket, Qt::DirectConnection); connect(tcpThread[socketDescriptor], &TcpThread::closeConnection, this, &TcpServer::closeConnection); connect(tcpThread[socketDescriptor], &TcpThread::showMessage, this, &TcpServer::readMessage); connect(tcpThread[socketDescriptor], &TcpThread::refreshDatabase, this, &TcpServer::readSelectSql); tcpThread[socketDescriptor]->start(); seamphore->release(); } //读取刷新数据库信息 void TcpServer::readSelectSql() { emit selectSql(); } //关闭连接 void TcpServer::closeConnection(qintptr socket) { tcpThread.remove(socket); if (tcpThread.isEmpty()) { sqlNum = 0; if (closeMode) { emit closeFinished(); } } } //读取消息 void TcpServer::readMessage(const QString &str) { emit showMessage(str); }
下面再实现QTcpSocket多线程类,继承QThread后重写就行了,可以把读取写入数据一起放在这个线程里面
//TcpThread.h #pragma once #include <QThread> #include <qtcpsocket.h> #include <qsqlquery.h> class TcpThread : public QThread { Q_OBJECT public: TcpThread(const int &s, qintptr id, QObject* parent = nullptr); ~TcpThread(); void run(); int checkSignIn_1(const QString& strName, const QString& passWord, const QString& cpuid); int checkSignIn_2(const QString& strName, const QString& passWord, const QString& cpuid); int checkSignUp_1(const QString& strName, const QString& passWord, const QString& cpuid); int checkSignUp_2(const QString& strName, const QString& passWord, const QString& cpuid); //关闭TCP线程 void closeTcpSocket(); //设置是否打开注册 void setOpen(bool mode); private: QTcpSocket* tcpSocket; bool open; QSqlDatabase *db; QSqlQuery *query; qintptr socketDescriptor; QString ip; int sqlNum; //保存数据库连接数 private slots: //读取消息 void readMessage(); //断开连接 void disconnectFinish(); //退出完成 void quitFinished(); signals: //刷新数据库 void refreshDatabase(); //发送消息 void showMessage(const QString &str); //关闭连接 void closeConnection(qintptr socket); };
//TcpThread.cpp #include "TcpThread.h" #include <QTime> #include <qhostaddress.h> #include <qsqldatabase.h> #include <QJsonDocument> #include <QJsonObject> #include <QJsonValue> TcpThread::TcpThread(const int &s, qintptr id, QObject* parent) : sqlNum(s), socketDescriptor(id), QThread(parent) { open = false; db = nullptr; query = nullptr; tcpSocket = nullptr; } TcpThread::~TcpThread() { if (db != nullptr) { delete db; delete query; } if (tcpSocket != nullptr) tcpSocket->deleteLater(); } void TcpThread::run() { if (db == nullptr) { db = new QSqlDatabase; if (QSqlDatabase::contains(QString("%1").arg(sqlNum))) QSqlDatabase::removeDatabase(QString("%1").arg(sqlNum)); *db = QSqlDatabase::addDatabase("QSQLITE", QString("%1").arg(sqlNum)); db->setDatabaseName("data.db"); query = new QSqlQuery(*db); } if (tcpSocket == nullptr) { tcpSocket = new QTcpSocket; connect(tcpSocket, &QTcpSocket::readyRead, this, &TcpThread::readMessage, Qt::DirectConnection); //如果有可读的数据 发出信号时立即调用 connect(tcpSocket, &QTcpSocket::disconnected, this, &TcpThread::disconnectFinish); connect(this, &TcpThread::finished, this, &TcpThread::quitFinished); } if (!tcpSocket->setSocketDescriptor(socketDescriptor)) { emit showMessage(QStringLiteral("设置套接字错误 %1").arg(socketDescriptor)); return; } ip = tcpSocket->peerAddress().toString().replace("::ffff:", ""); this->exec(); } //神秘京东工具登录 int TcpThread::checkSignIn_1(const QString& strName, const QString& passWord, const QString& cpuid) { if (!db->isOpen()) db->open(); query->exec(QString("select * from accounts where name = '%1' and password = '%2';").arg(strName).arg(passWord)); //查询用户 query->next(); if (query->isValid()) { if (query->value(3).toString() >= QDateTime::currentDateTime().toString("yyyy-MM-dd")) { if (query->value(4).toString() == cpuid) { return 1; } else return 3; } else return 2; } db->close(); return 0; } //JD Key登录 int TcpThread::checkSignIn_2(const QString& strName, const QString& passWord, const QString& cpuid) { if (!db->isOpen()) db->open(); query->exec(QString("select * from keyaccounts where name = '%1' and password = '%2';").arg(strName).arg(passWord)); //查询用户 query->next(); if (query->isValid()) { if (query->value(3).toString() >= QDateTime::currentDateTime().toString("yyyy-MM-dd")) { if (query->value(4).toString() == cpuid) { return 1; } else return 3; } else return 2; } db->close(); return 0; } //神秘京东工具注册 int TcpThread::checkSignUp_1(const QString& strName, const QString& passWord, const QString& cpuid) { if (open) { if (!db->isOpen()) db->open(); query->exec(QString("select * from accounts where name = '%1';").arg(strName)); //查询用户 query->next(); if (query->isValid()) { return 0; } query->exec(QString("insert into accounts values(NULL,'%1','%2','%3','%4')").arg(strName).arg(passWord).arg(QDateTime::currentDateTime().toString("yyyy-MM-dd")).arg(cpuid)); db->close(); emit refreshDatabase(); return 1; } else return 3; } //JD Key注册 int TcpThread::checkSignUp_2(const QString& strName, const QString& passWord, const QString& cpuid) { if (open) { if (!db->isOpen()) db->open(); query->exec(QString("select * from keyaccounts where name = '%1';").arg(strName)); //查询用户 query->next(); if (query->isValid()) { return 0; } query->exec(QString("insert into keyaccounts values(NULL,'%1','%2','%3','%4')").arg(strName).arg(passWord).arg(QDateTime::currentDateTime().toString("yyyy-MM-dd")).arg(cpuid)); db->close(); emit refreshDatabase(); return 1; } else return 3; } //关闭TCP线程 void TcpThread::closeTcpSocket() { QMetaObject::invokeMethod(tcpSocket, std::bind(&QTcpSocket::close, tcpSocket)); } //设置是否打开注册 void TcpThread::setOpen(bool mode) { open = mode; } //读取连接数据 void TcpThread::readMessage() { QStringList dataList; QString data = tcpSocket->readAll(); QByteArray allData = data.toUtf8(); QJsonParseError error; QJsonDocument doc = QJsonDocument::fromJson(allData, &error); if (error.error == QJsonParseError::NoError) { QJsonObject rootObject = doc.object(); if (rootObject.contains("Sql")) { QJsonValue jsonValue = rootObject.value("Sql"); dataList << jsonValue.toString(); } if (rootObject.contains("Type")) { QJsonValue jsonValue = rootObject.value("Type"); dataList << jsonValue.toString(); } if (rootObject.contains("User")) { QJsonValue jsonValue = rootObject.value("User"); dataList << jsonValue.toString(); } if (rootObject.contains("Pass")) { QJsonValue jsonValue = rootObject.value("Pass"); dataList << jsonValue.toString(); } if (rootObject.contains("Cpu")) { QJsonValue jsonValue = rootObject.value("Cpu"); dataList << jsonValue.toString(); } } if (dataList.size() == 5) { QJsonObject rootObject; if (dataList[0] == "0") { int ret; if (dataList[1] == "A") //注册 ret = checkSignUp_1(dataList[2], dataList[3], dataList[4]); else if (dataList[1] == "B") //登录 ret = checkSignIn_1(dataList[2], dataList[3], dataList[4]); else return; rootObject.insert("Type", dataList[1]); if (ret == 1) rootObject.insert("Ret", "true"); else rootObject.insert("Ret", "false"); rootObject.insert("Ret_Code", QString("%1").arg(ret)); } else if (dataList[0] == "1") { int ret; if (dataList[1] == "A") //注册 ret = checkSignUp_2(dataList[2], dataList[3], dataList[4]); else if (dataList[1] == "B") //登录 ret = checkSignIn_2(dataList[2], dataList[3], dataList[4]); else return; rootObject.insert("Type", dataList[1]); if (ret == 1) rootObject.insert("Ret", "true"); else rootObject.insert("Ret", "false"); rootObject.insert("Ret_Code", QString("%1").arg(ret)); } doc.setObject(rootObject); tcpSocket->write(doc.toJson()); } else { QJsonObject rootObject; rootObject.insert("Ret_Code", QStringLiteral("未知指令")); doc.setObject(rootObject); tcpSocket->write(doc.toJson()); } } //断开连接信号 void TcpThread::disconnectFinish() { this->quit(); } //退出完成 void TcpThread::quitFinished() { emit closeConnection(socketDescriptor); this->deleteLater(); }