1.目的
主要是为了使得每个客户端进来后,分配一个线程进行处理。
实现多线程方法有两种,分别是继承QObject或者继承QThread。本文使用继承QObject,并使用moveToThread将客户端Socket移动到线程中执行。
2.实现方法
- 首先继承QTcpServer,重写incomingConnection方法。incomingConnection方法主要当新的客户端Socket连接后,会为其分配新的套接字描述符。最后通过emit newconnection()保证不断有新的连接进入,并进行处理。
- 通过QMap或者QList来存储连接进入的客户端Socket。(实际开发,还需要保证线程的安全性,应当使用std::mutex来确保线程的安全)
- 再继承QTcpSocket(当然不继承直接使用也行,需要在myTcpServer中的incomingConnection中使用setSocketDescriptor)。
3.具体代码如下:
- myTcpServer.h
#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H
#include <QTcpServer>
#include <QObject>
#include <qthread.h>
#include <qmap.h>
#include <mutex>
#include "mytcpsocket.h"
class myTcpServer : public QTcpServer
{
Q_OBJECT
public:
myTcpServer();
/*
Main Widget 基本用法:
myTcpSever *server = new myTcpServer();
//监听所有IP地址的端口
server->listen(QHostAddress::Any, PORT);
//有新的连接进来,触发incomingConnection函数
//myTcpSocket 开辟一个线程进行处理
//myTcpSocket 先设置字符描述符
//myTcpsocket 读数据,并发送处理数据信号给myTcpSever
//myTcpsocket 可通过myTcpServer调用haddleData函数对传来的数据进行处理
//myTcpsocket 数据处理完后,myTcpServer通过setData将处理后的数据进行发送回去
//myTcpsocket 断开连接,触发socketdisconnect信号,myTcpServer进行处理(socketdisconnect函数)
//myTcpsocket 发送disconnected信号,处理它的线程退出
//线程任务完成后,释放myTcpSocket
//实际开发,通过Mutex进行对线程的保护,保证其安全性(std::lock_guard<std::mutex>)
*/
signals:
void sendData(QByteArray &data, qintptr socketDescripto);
void clientconnect(qintptr Id, QString ip, quint16 port);
private slots:
void haddleData(qintptr handle, QString ip, quint16 port, QByteArray &data);
void socketdisconnect(qintptr handle, QString ip, quint16 port);
void setData(QByteArray &data, qintptr socketDescripto);
protected:
void incomingConnection(qintptr socketDescriptor);
public:
QMap<qintptr, myTcpSocket*> getTcpClients();
private:
QMap<qintptr, myTcpSocket*> TcpClients;
//std::mutex m;
};
#endif // MYTCPSERVER_H
- myTcpServer.h
#include "mytcpserver.h"
myTcpServer::myTcpServer()
{
}
void myTcpServer::haddleData(qintptr handle, QString ip, quint16 port, QByteArray &data)
{
}
void myTcpServer::socketdisconnect(qintptr handle, QString ip, quint16 port)
{
myTcpSocket *clientsoket = TcpClients.value(handle);
TcpClients.remove(handle);
clientsoket->deleteLater();
emit socketdisconnect(handle, ip, port);
}
void myTcpServer::setData(QByteArray &data, qintptr socketDescripto)
{
emit sendData(data, socketDescripto);
}
void myTcpServer::incomingConnection(qintptr socketDescriptor)
{
myTcpSocket *clientsoket = new myTcpSocket(socketDescriptor);
QThread *thread = new QThread();
connect(this, &myTcpServer::sendData,
clientsoket, &myTcpSocket::sendData);
connect(this, &myTcpServer::sendData,
this, &myTcpServer::setData);
connect(clientsoket, &myTcpSocket::haddleData,
this, &myTcpServer::haddleData);
connect(clientsoket, &myTcpSocket::socketdisconnect,
this, &myTcpServer::socketdisconnect);
connect(clientsoket, &myTcpSocket::disconnected,
thread, &QThread::quit);
connect(thread, &QThread::finished,
clientsoket, &myTcpSocket::deleteLater);
clientsoket->moveToThread(thread);
thread->start();
TcpClients.insert(socketDescriptor, clientsoket);
//emit newconnection()也行;
emit clientconnect(clientsoket->socketDescriptor(), clientsoket->peerAddress().toString(), clientsoket->peerPort());//发送新的连接信号
}
QMap<qintptr, myTcpSocket *> myTcpServer::getTcpClients()
{
return this->TcpClients;
}
- myTcpSocket.h
#ifndef MYTCPSOCKET_H
#define MYTCPSOCKET_H
#include <QTcpSocket>
#include <QObject>
class myTcpSocket : public QTcpSocket
{
Q_OBJECT
signals:
void haddleData(qintptr handle, QString ip, quint16 port, QByteArray &data);
void socketdisconnect(qintptr handle, QString ip, quint16 port);
public slots:
void sendData(QByteArray &data, qintptr socketDescriptor);
void readData();
public:
myTcpSocket(qintptr Id, QObject *parent = nullptr);
virtual ~myTcpSocket();
private:
qintptr Id;
};
#endif // MYTCPSOCKET_H
- myTcpSocket.cpp
#include "mytcpsocket.h"
myTcpSocket::myTcpSocket(qintptr Id, QObject *parent)
:Id(Id)
,QTcpSocket(parent)
{
this->setSocketDescriptor(Id);
connect(this, &myTcpSocket::readyRead, [this](){
readData();
});
if(this->state() == QAbstractSocket::UnconnectedState)
emit socketdisconnect(this->socketDescriptor(),
this->peerAddress().toString(), this->peerPort());
}
myTcpSocket::~myTcpSocket()
{
}
void myTcpSocket::sendData(QByteArray &data, qintptr socketDescriptor)
{
if(Id == socketDescriptor){
qDebug() << "connect server success and send data";
this->write(data);
}
}
void myTcpSocket::readData()
{
QByteArray data;
while(this->bytesAvailable())
data = this->readAll();
emit haddleData(this->socketDescriptor(), this->peerAddress().toString(), this->peerPort(), data);
}
4. 具体代码结构如下图
- 编译,运行结果如下图