QTcpServer多线程实现

QT-TCP服务端开启多个线程处理收到多客户端发来的消息示例 一些用到的函数等解释: void incomingConnection ( int socketDescriptor ) 当有新连接可用时,QTcpServer将调用此虚拟函数。注意:如果希望将传入连接作为另一个线程中的新QTcpSocket对象处理,则必须将socketDescriptor传递给另一个线程,在那里创建QTcpSocket对象并使用其setSocketDescriptor()方法。 ... 阅读详情


目的:每个客户端连接的tcpSocket分别分配一个专门的线程来处理。

实现时分别继承QTcpServer和QTcpScoket实现出自己需要的类。

继承QTcpServer为每个客户端连接时分配线程,并接受处理tcpScoket的信号和槽、、还有发送信息,储存连接信息等。

继承QTcpScoket为处理通信数据和增加信号的参数,以便和tcpServer更好的配合。

首先是继承并重写QTcpServer的incomingConnection函数去自己实现tcpsocket连接的建立和分配。

其文档的默认描述为:

This virtual function is called by QTcpServer when a new connection is available. The socketDescriptor argument is the native socket descriptor for the accepted connection.

The base implementation creates a QTcpSocket, sets the socket descriptor and then stores the QTcpSocket in an internal list of pending connections. Finally newConnection() is emitted.

Reimplement this function to alter the server’s behavior when a connection is available.

If this server is using QNetworkProxy then the socketDescriptor may not be usable with native socket functions, and should only be used with QTcpSocket::setSocketDescriptor().

Note: If you want to handle an incoming connection as a new QTcpSocket object in another thread you have to pass the socketDescriptor to the other thread and create the QTcpSocket object there and use its setSocketDescriptor() method.

译文(谷歌翻译和自己简单的更正):

当QTcpServer有一个新的连接时这个虚函数被调用。该socketDescriptor参数是用于接受连接的本地套接字描述符。

该函数会创建一个QTcpSocket,并设置套接字描述符为socketDescriptor,然后存储QTcpSocket在挂起连接的内部清单。最后newConnection()被发射。

重新实现这个函数来改变服务器的行为,当一个连接可用。

如果该服务器使用QNetworkProxy那么socketDescriptor可能无法与原生socket函数使用,并且只能用QTcpSocket:: setSocketDescriptor()中使用。

注意:如果你想处理在另一个线程一个新的QTcpSocket对象传入连接,您必须将socketDescriptor传递给其他线程,并创建了QTcpSocket对象存在并使用其setSocketDescriptor()方法。

所以我们必须先重写这个函数:

下面先附上继承QTcpServer的自己的类声明,代码注释个人以为挺详细了:

01//继承QTCPSERVER以实现多线程TCPscoket的服务器。
02class MyTcpServer : public QTcpServer
03{
04    Q_OBJECT
05public:
06    explicit MyTcpServer(QObject *parent = 0);
07    ~MyTcpServer();
08signals:
09    void connectClient(const int , const QString & ,const quint16 );//发送新用户连接信息
10    void readData(const int,const QString &, quint16, const QByteArray &);//发送获得用户发过来的数据
11    void sockDisConnect(const int ,const QString &,const quint16 );//断开连接的用户信息
12    void sentData(const QByteArray &,const int);//向scoket发送消息
13public slots:
14    void setData(const QByteArray & data, const int  handle);//想用户发送消息
15    void readDataSlot(const int, const QString &, const quint16,const QByteArray &);//发送获得用户发过来的数据
16    void sockDisConnectSlot(int handle, QString ip, quint16 prot);//断开连接的用户信息
17 
18protected:
19    void incomingConnection(qintptr socketDescriptor);//覆盖已获取多线程
20private:
21    QMap<int,myTcpSocket *> * tcpClient;
22};

接着是我们重写void QTcpServer::incomingConnection(qintptr socketDescriptor)的实现:

01void MyTcpServer::incomingConnection(qintptr socketDescriptor)
02{
03    myTcpSocket * tcpTemp = new myTcpSocket(socketDescriptor);
04    QThread * thread = new QThread(tcpTemp);//把线程的父类设为连接的,防止内存泄漏
05    //可以信号连接信号的,我要捕捉线程ID就独立出来函数了,使用中还是直接连接信号效率应该有优势
06    connect(tcpTemp,&myTcpSocket::readData,this,&MyTcpServer::readDataSlot);//接受到数据
07    connect(tcpTemp,&myTcpSocket::sockDisConnect,this,&MyTcpServer::sockDisConnectSlot);//断开连接的处理,从列表移除,并释放断开的Tcpsocket
08    connect(this,&MyTcpServer::sentData,tcpTemp,&myTcpSocket::sentData);//发送数据
09    connect(tcpTemp,&myTcpSocket::disconnected,thread,&QThread::quit);//断开连接时线程退出
10    tcpTemp->moveToThread(thread);//把tcp类移动到新的线程
11    thread->start();//线程开始运行
12 
13    tcpClient->insert(socketDescriptor,tcpTemp);//插入到连接信息中
14    qDebug() <<"incomingConnection THREAD IS:" <<QThread::currentThreadId();
15    //发送连接信号
16    emit connectClient(tcpTemp->socketDescriptor(),tcpTemp->peerAddress().toString(),tcpTemp->peerPort());
17 
18}

用moveToThread来处理移动到新的线程。

其他的非重要的函数就不一一列出,但是别忘记在断开连接的槽中释放连接:

01void MyTcpServer::setData(const QByteArray &data, const int handle)
02{
03    emit sentData(data,handle);
04}
05 
06void MyTcpServer::sockDisConnectSlot(int handle, QString ip, quint16 prot)
07{
08    qDebug() <<"MyTcpServer::sockDisConnectSlot thread is:" << QThread::currentThreadId();
09 
10    myTcpSocket * tcp = tcpClient->value(handle);
11    tcpClient->remove(handle);//连接管理中移除断开连接的socket
12    delete tcp;//释放断开连接的资源、、子对象线程也会释放
13    emit sockDisConnect(handle,ip,prot);
14}

其次就是继承的QTcpSocket的声明,直接上代码把:

01//继承QTcpSocket以处理接收到的数据
02class myTcpSocket : public QTcpSocket
03{
04    Q_OBJECT
05public:
06    explicit myTcpSocket(qintptr socketDescriptor,QObject *parent = 0);
07 
08signals:
09    void readData(const int,const QString &,const quint16,const QByteArray &);//发送获得用户发过来的数据
10    void sockDisConnect(const int ,const QString &,const quint16 );//断开连接的用户信息
11public slots:
12    void thisReadData();//处理接收到的数据
13    void sentData(const QByteArray & ,const int);//发送信号的槽
14private:
15    qintptr socketID;//保存id,== this->socketDescriptor();但是this->socketDescriptor()客户端断开会被释放,
16                        //断开信号用this->socketDescriptor()得不到正确值
17};

这个实现其实更简单了、、、就把主要的信号槽连接部分附上把,还有发送数据需要注意下,我是用的Qt,其中信号槽用的新语法,而且配合的C++11的lambda表达式,你如果不清楚C++11,你最好先去看下C++11的文档。

01myTcpSocket::myTcpSocket(qintptr socketDescriptor, QObject *parent) :
02    QTcpSocket(parent),socketID(socketDescriptor)
03{
04    this->setSocketDescriptor(socketDescriptor);
05    //转换系统信号到我们需要发送的数据、、直接用lambda表达式了,qdebug是输出线程信息
06    connect(this,&myTcpSocket::readyRead,this,&myTcpSocket::thisReadData); //连接到收到数据的处理函数
07    connect(this,&myTcpSocket::readyRead, //转换收到的信息,发送信号
08            [this](){
09                qDebug() <<"myTcpSocket::myTcpSocket lambda readData thread is:" << QThread::currentThreadId();                 emit readData(socketID,this->peerAddress().toString(),this->peerPort() ,this->readAll());//发送用户发过来的数据
10            });
11    connect(this,&myTcpSocket::disconnected, //断开连接的信号转换
12            [this](){
13                qDebug() <<"myTcpSocket::myTcpSocket lambda sockDisConnect thread is:" << QThread::currentThreadId();                 emit sockDisConnect(socketID,this->peerAddress().toString(),this->peerPort());//发送断开连接的用户信息
14            });
15 
16    qDebug() << this->socketDescriptor() << " " << this->peerAddress().toString()
17                << " " << this->peerPort() << "myTcpSocket::myTcpSocket thread is " <<QThread::currentThreadId();
18}
19 
20void myTcpSocket::sentData(const QByteArray &data, const int id)
21{
22    //如果是服务器判断好,直接调用write会出现跨线程的现象,所以服务器用广播,每个连接判断是否是自己要发送的信息。
23    if(id == socketID)//判断是否是此socket的信息
24    {
25        qDebug() << "myTcpSocket::sentData" << QThread::currentThreadId();
26        write(data);
27    }
28}

整篇代码中出现了n个qDebug() << ,这个是我为了查看运行所在的线程所设,实际应用中这些都没用的、、你自己删除把、、自己测试的例子和源码我还是保留了、、毕竟时间长了都忘得,留着那天一看就一目了然的、、

这个每个连接分配一个线程,连接太多很耗资源的、、您可以自己更改下,把多个连接移到一个线程,但是那样,你需要保存线程信息,更要小心线程的分配和释放时、、可以自己做下、、我也欢迎大家来探讨、、

最新更新:添加线程管理类(应该算个线程池),单例类。可预先设置线程数或者每个线程处理多少连接。原来的代码主要变动在新建断开连接处更新了、、详细请见代码。

全部的代码测试例子,服务端和客户端,我传到了我的github上了,附上项目地址:https://github.com/dushibaiyu/QtTcpThreadServer


http://www.dushibaiyu.com/2013/12/qtcpserver%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%AE%9E%E7%8E%B0.html

Qt WebSocket 3)保持连接状态:与 HTTP 不同的是,WebSocket 需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息;在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行。1)较少的控制开销:在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小;5)可以支持扩展:WebSocket 定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如: ws://example.com:80/some/path。 阅读详情

相关推荐

Qt实现简易的多线程TCP服务器(附源码)

1.首先我们搞清楚,这个类是负责干嘛的?这个类我们要继承QTcpServer,重写虚函数incomingConnetion2.这是头文件,如果有报错,注意看使用#pragma once没有,因为可能涉及到头文件重复包含Q_OBJECTpublic:private://重写虚函数private://用来保存连接进来的套接字,存到ComboBox中//再包含一个widget对象//widget.hQ_OBJECTpublic:~Widget();

z1zyy的博客 4554

基于Qt的多线程TCP即时通讯软件的设计与实现

基于Qt的多线程TCP即时通讯软件的设计与实现 本文将从涉及到主要技术开始,讲解使用Qt来实现一个支持多客户端链接的多线程TCP服务器及其客户端的设计与实现的解决方案。 注:本文使用的开发环境为Qt5.15.2,使用MSVC2019_64编译器,C++11及以上

SWULWJ的博客 1万+

QTcpServer实现多线程服务器

QTcpServer实现多线程服务器 当QTcpServer收到一个客户端连接的时候,会发送一个信号void newConnection()。在接收信号的槽函数中调用nextPendingConnection()函数获得与客户端连接的QTcpSocket对象。但是这个对象只能在主线程中使用,在多线程时是不能使用的。 我们查看nextPendingConnection()函数的文档说明。 说明很清楚的告诉我们这个QTcpSocket是不能在其他线程中使用的。并且还告诉我们应该如何实现多线程。那就是重写in

seamancsdn的博客 1507

QT学习:QTcpServer多线程实现

QTcpServer多线程实现 目的:每个客户端连接的tcpSocket分别分配一个专门的线程来处理。 实现时分别继承QTcpServer和QTcpScoket实现出自己需要的类。 继承QTcpServer为每个客户端连接时分配线程,并接受处理tcpScoket的信号和槽、、还有发送信息,储存连接信息等。 继承QTcpScoket为处理通信数据和增加信号的参数,以便和tcpServer更好的配合。 首先是继承并重写QTcpServer的incomingConnection函数去自己实现tcpsoc

zjy900507的博客 4632

使用QTcpServer创建一个简单的服务器程序之二:多线程服务器(3)-线程池实现

首先是继承一个线程类,加入我们需要的一些基本信息。 class MyThread : public QThread { public: MyThread(); ~MyThread(); virtual void run(); QList<MyTcpSocket *> m_clientList;//每个线程维护的客户端列表 }; MyThread...

993

使用QTcpServer创建一个简单的服务器程序之二:多线程服务器(4)-服务端实现

前面说了服务端类MyTcpServer只负责监听连入的客户端,并把这个客户端丢入线程池中。并且还要接收来自界面类的一些请求,并最终通过它管理的线程池来实现。这其中最重要函数就是重写incomingConnection //这里包含一个线程池的对象和一个客户端链表 MyThreadPool m_pool;//线程池 QList<MyTcpSocket*> m_list...

902

Qt封装QTcpServer参考资料--QTcpServer多线程实现

目的:每个客户端连接的tcpSocket分别分配一个专门的线程来处理。 实现时分别继承QTcpServer和QTcpScoket实现出自己需要的类。 继承QTcpServer为每个客户端连接时分配线程,并接受处理tcpScoket的信号和槽、、还有发送信息,储存连接信息等。 继承QTcpScoket为处理通信数据和增加信号的参数,以便和tcpServer更好的配合。 首先是继承并重写QTc...

weixin_30326515的博客 172

qt QTcpServer多线程

QTcpServer多线程 每个客户端连接的tcpSocket分别分配一个专门的线程来处理。 核心思想:继承并重写QTcpServer的incomingConnection函数去自己实现tcpsocket连接的建立和分配。 incomingConnection函数说明: 当QTcpServer有一个新的连接时这个虚函数被调用。该socketDescriptor参数是用于接受连接的本地套接字描述符。 该函数会创建一个QTcpSocket,并设置套接字描述符为socketDescriptor,然后存储QTcpSocket在挂起连接的内部清单。最后newConnection()被发射。 重新实现这个函数来改变服务器的行为,当一个连接可用。 注意:如果你想处理在另一个线程一个新的QTcpSocket对象传入连接,您必须将socketDescriptor传递给其他线程,并创建了QTcpSocket对象存在并使用其setSocketDescriptor()方法。

使用pyqt的QThread实现多线程的QTcpServer

本文章采用与《使用pyqt的QUdpSocket传文本信息、用QTcpServer传文件的样例》(该文章是从C++上的Qt收发文件的代码翻译过来的,个人认为过于复杂不易理解)不同的写法实现TCP收发文件,并增加多线程的功能。本文章的写法更接近于socketserver.ThreadingUDPServer、socketserver.ThreadingTCPServer的写法,可参考《使用socketserver的ThreadingUDPServer、ThreadingTCPServer实现收发消息和文件》。

技术宅毁灭世界 2196

电容DAC版图布局中的对称艺术:从二维共质心到误差最小化

本文深入探讨了电容DAC版图布局中的对称艺术,重点介绍了二维共质心技术如何有效最小化误差。通过分析系统误差和随机误差的来源,详细解析了共质心布局的核心技术及优化策略,包括梯度误差补偿和寄生参数平衡方法。实战案例展示了该技术在12位SAR ADC设计中的应用效果,为高精度集成电路设计提供了重要参考。

weixin_29300241的博客 581

解决linux 2.5G网卡驱动问题

解决linux 2.5G网卡驱动问题 关键词:2.5G网卡驱动,ubuntu,安装,2.5G Ethernet LINUX driver,Realtek网卡驱动 由于2.5G网卡较新,各linux发行版的通用驱动已不适用,新装的系统会出现无法上网问题,由于国内网络环境去Realtek官网很难下载到驱动文件,故本文提供github上的2.5G Ethernet LINUX driver r8125 for kernel up to 5.6的版本驱动文件r8125-9.003.05.tar.bz2各位可以自

poorguy_aos的博客 1万+

QTcpServer多线程实现 简单示例

多线程实现 目的:每个客户端连接的tcpSocket分别分配一个专门的线程来处理。 内容:界面输入要监听的IP地址和端口,点击监听即可 如果输入IP为空,默认是监听本地所有IP. 输入框输入字符,点击发送按钮发送。 客户端连接后,发送的数据显示在接收框中。 头文件: #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include "tcpserver.h" namespace Ui { class Widget; }

君君的博客 1089

方案设计之亿级排行榜方案设计

该方案通过 “Redis Zset 为核心 + 分治策略为骨架 + 多级优化为细节”,在亿级用户场景下实现了:本质是将 “亿级大问题” 拆解为 “千万级小问题”,用分布式思想和精细化设计平衡性能、可用性与成本。

shine0312的专栏 1100

Qtcpserver多线程服务器实现及单线程服务器示例

Qtcpserver多线程服务器实现及单线程服务器示例 【下载地址】Qtcpserver多线程服务器实现及单线程服务器示例 该项目提供了一个基于Qtcpserver的多线程服务器实现,并附带单线程服务器示例,帮助开发者轻松构建高性能网络通信服务。多线程服务器充分利用系统资源,高效处理并发连接;单线程服务器则适合简单场景。...

gitblog_06717的博客 323

ESP32-P4开发板实战:从零配置VSCode环境到点亮MIPI-DSI屏幕(避坑指南)

本文详细介绍了ESP32-P4开发板在VSCode环境下的配置流程,包括SDK安装、idf_component.yml依赖管理,以及MIPI-DSI屏幕驱动的实现方法。通过实战指南帮助开发者避开常见配置陷阱,快速完成从环境搭建到屏幕点亮的全流程,适用于物联网和嵌入式开发场景。

pp12345的博客 741

Auto.js实战:从解锁手机到自动阅读的全流程避坑指南(MIUI系统适配版)

本文详细介绍了Auto.js在MIUI系统下的自动化操作全流程优化指南,包括设备唤醒、应用启动、界面交互等关键环节的实战技巧。特别针对MIUI系统的变速检测机制和电源管理策略,提供了有效的避坑方案和性能优化建议,帮助开发者实现从解锁手机到自动阅读的稳定运行。

醉三国 246
上一篇: 为QT的Webkit 编写插件
下一篇: QHeaderView 禁用某些列排序和添加QCheckBox控件
zdpyly21
博客等级 码龄12年 2粉丝 5原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值