QT实现高并发多线程处理多个Socket客户端

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. 具体代码结构如下图

  • 编译,运行结果如下图

 

 

 

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱喝牛奶的奶牛ovo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值