使用QtQSignalMapper建立服务器多客户端处理
原因:
每当新建立一个连接时会发出一个newConnection()
信号,在处理信号函数中调用nextPendingConnection()
会建立一个新的通信Socket,但是多个客户端连接时,上以个Socket会被覆盖,如果使用QList储存所有客户端时,QList内的Socket无法及时通过readyRead()
信号读取信息等问题,需要不断遍历QList的来获取信号,而且效率不高.
解决方案:
通过QSignalMapper与QList组合,将readyRead()
信号全部绑定到QSignalMapper
里面,在将Socket添加到QSignalMapper``中时建立与QList一直的索引,每次
QSignalMapper发出'
readyRead()`'信号时会同时发出索引值,从而取得当前通信的Socket
- 实现void incomingConnection(qintptr socketDescriptor)虚函数
//.h文件
#ifndef __REWRITETCPSERVER
#define __REWRITETCPSERVER
#include <QObject>
#include <QTcpServer>
class RewriteTcpServer : public QTcpServer{
Q_OBJECT
protected:
void incomingConnection(qintptr socketDescriptor);
signals:
void sendSocket(qintptr ocketDescriptor);
public:
RewriteTcpServer(QObject* parent);
~RewriteTcpServer();
};
#endif //__REWRITETCPSERVER
//cpp文件
#include "RewriteTcpServer.h"
RewriteTcpServer::RewriteTcpServer(QObject* parent)
: QTcpServer(parent) {
}
//重写tcpserver将套接字描述符转发到其他线程中
void RewriteTcpServer::incomingConnection(qintptr socketDescriptor) {
emit sendSocket(socketDescriptor);
}
RewriteTcpServer::~RewriteTcpServer()
{
}
//.h
//服务器监听类
#ifndef __SERVERNETWORK
#define __SERVERNETWORK
#include "QObject"
#include "RewriteTcpServer.h"
#include "SocketFactory.h"
#include "ConnectSqlPool.h"
class ServerNetwork : public QObject
{
Q_OBJECT
public:
ServerNetwork(QObject* parent = 0);
~ServerNetwork();
signals:
void repetionSendSocketDescriptor(qintptr SocketDescriptor);
protected slots:
void receptionSocketDescriptor(qintptr SocketDescriptor);
private:
RewriteTcpServer* listenSocker;//监听类
SocketFactory * socketFactory;//socket工厂类
};
#endif //__SERVERNETWORK
//cpp
#include "ServerNetwork.h"
ServerNetwork::ServerNetwork(QObject* parent) : QObject(parent) {
socketFactory = new SocketFactory(this); //初始化工厂类
listenSocker = new RewriteTcpServer(this);//客户端监听
if (listenSocker->listen(QHostAddress::Any, 9090)) {
qDebug() << "当前网络监听成功......!";
}
else {
qDebug() << listenSocker->errorString();
}
connect(listenSocker, &RewriteTcpServer::sendSocket, this, &ServerNetwork::receptionSocketDescriptor);
connect(this, &ServerNetwork::repetionSendSocketDescriptor, socketFactory, &SocketFactory::acceptSocketDescriptor);
QTimer* timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, []() {ConnectSqlPool::autoClearMoredb(); qDebug() << "数据库清理定时器启动了"; });
timer->start(60 * 60 * 1000);
}
void ServerNetwork::receptionSocketDescriptor(qintptr SocketDescriptor) { //将socket描述符发送到工厂类中
emit repetionSendSocketDescriptor(SocketDescriptor);
}
ServerNetwork::~ServerNetwork() {
}
//.h
#ifndef __SOCKETFACTORY
#define __SOCKETFACTORY
#include <QObject>
#include <QObject>
#include <QList>
#include <QTcpSocket>
#include <QSignalMapper>
#include <QJsonObject>
#include <QJsonDocument>
#include "TranslateJson.h"
#include "ServerLogin.h"
#include "AddPlantInfo.h"
#include <QDataStream>
#include <QThread>
#include "DatasPackaging.h"
class SocketFactory : public QObject {
Q_OBJECT
public:
enum {
LOGIN = 1001,
ADD = 1002,
SELECT = 1003,
AMEND = 1004,
UPDATE = 1005,
EXPORT = 1006,
DELETE = 1007
};
SocketFactory(QObject* parent = 0);
~SocketFactory();
signals:
void sendExportsignal(QMap<int, QList<QList<QVariant>>> m_map, int index); //导入数据线程信号
void sendSelectsignal(QMap<int, QList<QList<QVariant>>> m_map, int index); //返回数据列表线程信号
public slots:
void acceptSocketDescriptor(qintptr SocketDescriptor); //接收socket描述符
void dispatchSocketInfo(int index); //派发客户端的连接
void socketState(int index); //客户端退出并清除list无效客户端
void clearDatasSize(); //清除接收数据
void feedbackExportInfo(bool result, int index); //导入信息反馈回客户端
void feedbackSelectResult(const bool result, const QList<QList<QVariant>> m_lists, const int index);//查询数据反馈
private:
QList<QTcpSocket*>* listSockt;
QSignalMapper * mapper;
QSignalMapper * SocketDisconnectedSignals;
TranslateJson translateJson;
QThread * m_thread;
AddPlantInfo * m_addPlantInfo;
DatasPackaging * datapack;
qint64 sizeDatas;
QByteArray countDatas;
};
#endif
//cpp
#include "SocketFactory.h"
SocketFactory::SocketFactory(QObject* parent)
: QObject(parent), listSockt(new QList<QTcpSocket*>), mapper(new QSignalMapper(this)),
SocketDisconnectedSignals(new QSignalMapper(this)), datapack(new DatasPackaging(this)) {
//导入excel多线程
m_thread = new QThread;
m_addPlantInfo = new AddPlantInfo;
m_addPlantInfo->moveToThread(m_thread);
//初始化交大数据判断字节数
sizeDatas = 0;
countDatas.clear();
//导入线程信号
connect(this, &SocketFactory::sendExportsignal, m_addPlantInfo, &AddPlantInfo::ExportPlantDatas);
connect(this, &SocketFactory::sendSelectsignal, m_addPlantInfo, &AddPlantInfo::plantInfoSelect);
connect(m_addPlantInfo, &AddPlantInfo::sendExportResult, this, &SocketFactory::feedbackExportInfo);
connect(m_addPlantInfo, &AddPlantInfo::sendPalntResult, this, &SocketFactory::feedbackSelectResult);
//socket列表
connect(mapper, &QSignalMapper::mappedInt, this, &SocketFactory::dispatchSocketInfo);
connect(mapper, &QSignalMapper::mappedInt, this, &SocketFactory::socketState);
qDebug() << "工厂类启动" << "当前线程ID:" << QThread::currentThreadId();
}
//生产socket并储存进行分类管理
void SocketFactory::acceptSocketDescriptor(qintptr SocketDescriptor) {
QTcpSocket* tempSocket = new QTcpSocket;
if (tempSocket->setSocketDescriptor(SocketDescriptor)) {
qDebug() << "IP:" << tempSocket->peerAddress().toString() << "端口:" << tempSocket->peerPort() << "客户端连接";
listSockt->append(tempSocket);
mapper->setMapping(listSockt->last(), listSockt->length() - 1);
SocketDisconnectedSignals->setMapping(listSockt->last(), listSockt->length() - 1);
connect(listSockt->last(), SIGNAL(readyRead()), mapper, SLOT(map()));
connect(listSockt->last(), SIGNAL(stateChanged(QAbstractSocket::SocketState)), mapper, SLOT(map()));
}
else {
qDebug() << "连接错误,错误原因:" << tempSocket->errorString();
}
}
//派发socket
void SocketFactory::dispatchSocketInfo(int index) {
//大量数据导致readAll无法全部接收,进行多次接收的判断
QByteArray str = listSockt->at(index)->readAll();
if (!str.isEmpty()) {
if (sizeDatas == 0) {
//获取头信息
QDataStream in(str);
in >> sizeDatas;
qDebug() << "接收的数据大小" << sizeDatas;
}
if (countDatas.size() < sizeDatas) {
countDatas.append(str);
qDebug() << "接收大量数据的字节数:" << countDatas.size();
}
if (sizeDatas == countDatas.size()) {
QDataStream indata(countDatas);
qint64 headersize;
QMap<int, QList<QList<QVariant>>> m_datas;
indata.setVersion(QDataStream::Qt_6_2);
indata >> headersize >> m_datas;
switch (m_datas.firstKey()) {
case LOGIN: {
ServerLogin login;
login.sendLoginInfo(listSockt->at(index), m_datas);
clearDatasSize();
break;
}
case ADD: {
AddPlantInfo addPlant;
addPlant.addplantinfo(listSockt->at(index), m_datas);
clearDatasSize();
break;
}
case EXPORT: {
m_thread->start();//线程反馈后的信息回复
emit sendExportsignal(m_datas, index);
clearDatasSize();
break;
}
case SELECT: {
m_thread->start();//完成查询信息处理
sendSelectsignal(m_datas, index);
clearDatasSize();
break;
}
case DELETE: {
AddPlantInfo addPlant;
addPlant.deletePlantInfo(listSockt->at(index), m_datas);
clearDatasSize();
break;
}
case UPDATE: {
qDebug() << "更新数据进行";
AddPlantInfo updatePlant;
updatePlant.updatePlantInfo(listSockt->at(index), m_datas);
clearDatasSize();
break;
}
default:
break;
}
}
}
}
//清除无效客户端
void SocketFactory::socketState(int index) {
if (listSockt->at(index)->state() == QAbstractSocket::UnconnectedState) {
//如果当前客户端断开或无效客户端时,关闭当前客户端并从list中删除
QTcpSocket* closeSocket = listSockt->at(index);
qDebug() << "IP:" << listSockt->at(index)->peerAddress().toString().trimmed()
<< "端口:" << listSockt->at(index)->peerPort() << "客户端退出了";
mapper->removeMappings(closeSocket);
SocketDisconnectedSignals->removeMappings(closeSocket);
closeSocket->close();
listSockt->removeAt(index);
}
}
void SocketFactory::clearDatasSize() {
sizeDatas = 0;
countDatas = NULL;
}
//导入信息反馈函数
void SocketFactory::feedbackExportInfo(bool result, int index) {
QByteArray m_by;
datapack->datasPackging(1003, result, m_by);
if (!m_by.isEmpty()) {
listSockt->at(index)->write(m_by, m_by.size());
}
m_thread->quit();
m_thread->wait();
}
//返回车间信息表
void SocketFactory::feedbackSelectResult(const bool result, const QList<QList<QVariant>> m_lists, const int index) {
QByteArray m_by;
datapack->datasPackging(1004, m_lists, m_by);
if (!m_by.isEmpty()) {
listSockt->at(index)->write(m_by, m_by.size());
}
m_thread->quit();
m_thread->wait();
}
SocketFactory::~SocketFactory() {
delete m_thread;
delete m_addPlantInfo;
delete listSockt;
}