QT TCP多线程网络通信

学习目标: TCP网络通信编程

学习前置环境

运行环境:qt creator 4.12

QT TCP网络通信编程-CSDN博客

Qt 线程 QThread类详解-CSDN博客

学习内容

使用多线程技术实现服务端计数器

 核心代码

客户端

客户端:负责连接服务端,每次连接次数+1。以及连接的报错信息

#include "dialog.h"
#include "ui_dialog.h"
#include<QDebug>
Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);
    ui->server_ip->setText("127.0.0.1");
    ui->server_port->setText("8888");
    clientSocket =new QTcpSocket;
    setWindowTitle("连接计数器客户端");
    //连接错误回调
    QObject::connect(clientSocket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error)
                     , this, [this](QAbstractSocket::SocketError error){
        switch (error) {
        case QAbstractSocket::RemoteHostClosedError: // 远程主机关闭连接
           // QMessageBox::information(this, "提示", "远程主机关闭连接", QMessageBox::Yes);
            break;

        case QAbstractSocket::HostNotFoundError: // 找不到主机地址
            QMessageBox::information(this, "提示", "找不到主机地址", QMessageBox::Yes);
            break;

        case QAbstractSocket::ConnectionRefusedError: // 连接被对方拒绝(或者超时)
            QMessageBox::information(this, "提示", "连接被对方拒绝(或者超时)", QMessageBox::Yes);
            break;

        default:
            QMessageBox::information(this, "提示", tr("致命错误为:").arg(clientSocket->errorString()), QMessageBox::Yes);
        }
        ui->request->setEnabled(true);
        ui->close->setEnabled(true);
    });
    //当 socket 成功连接到服务器时,会发射 connected() 信号。
    connect(clientSocket,&QTcpSocket::connected,this,[this](){
        QString str ="已经连接到服务器端\n服务器端ip:"+clientSocket->peerAddress().toString()+"服务器端port:"+QString::number(clientSocket->peerPort());
        //QMessageBox::information(this, "提示",str , QMessageBox::Yes);
        ui->request->setEnabled(false);
        ui->close->setEnabled(true);


            QString msg=ui->currentv->text()+'\n';
            clientSocket->write(msg.toUtf8(),msg.length());
            int count =(ui->currentv->text().toUInt());
            ui->currentv->setNum(++count);


    });
    //当 socket 与服务器断开连接时,会发射 disconnected() 信号。
    connect(clientSocket,&QTcpSocket::disconnected,this,[this](){
        QString str ="已断开与服务器端的连接\n服务器端ip:"+clientSocket->peerAddress().toString()+"服务器端port:"+QString::number(clientSocket->peerPort());
        //QMessageBox::information(this, "提示",str , QMessageBox::Yes);


        clientSocket->close();


    });


    ui->request->setEnabled(true);
    ui->close->setEnabled(true);



}

Dialog::~Dialog()
{
    delete ui;
}


void Dialog::on_request_clicked()
{


    clientSocket->connectToHost(ui->server_ip->text(),ui->server_port->text().toInt());

}

void Dialog::on_close_clicked()
{
    clientSocket->close(); // 取消已有的连接  后续触发断开回调
    ui->request->setEnabled(true);
    ui->close->setEnabled(false);
}

服务端

新连接请求类

通过继承重写的方式,实现新连接的回调操作。当然你也可以使用信号槽机制。如

connect(tcpServer, &QTcpServer::newConnection,对象,行为)。

实现功能:交给线程池处理,绑定实现连接断开前,把公用计数器+1操作,释放并清理资源。可以理解为绑定亡语操作,死后(连接断开)触发。

#ifndef TCPNEWCONNET_H
#define TCPNEWCONNET_H

#include"writethread.h"
#include"dialog.h"


class Dialog;


class TcpNewConnet : public QTcpServer  //基于重写虚函数 实现新连接回调函数
{
Q_OBJECT
public:
    TcpNewConnet()=default;
    ~TcpNewConnet()=default;
    TcpNewConnet(QObject *parent=0)
        :QTcpServer(parent)
    {
        dlgs =(Dialog*)parent;

    }
protected:
    // 当有新连接的时候会自动调用此函数
  void TcpNewConnet::incomingConnection(qintptr socketdescriptor){
    WriteThread *thread=new WriteThread(socketdescriptor,0);

   // 此处用于处理对话框显示统计访问次数信息
   connect(thread,&QThread::finished,dlgs,&Dialog::slotsdispFunc);

   connect(thread,&QThread::finished,thread,&QThread::deleteLater);

   thread->start(); // 通过执行这条语句来调用run()函数
}


    Dialog *dlgs;
};

#endif // TCPNEWCONNET_H

多线程类

依然是通过重写的方式,注意点是Tcpsocket的生命周期,当过了{}作用域会自动释放这条连接。实现了客户端连接成功,再释放。

功能:创造一个连接,然后等这个连接死亡。触发亡语操作。

#include "writethread.h"




WriteThread::WriteThread(int socketdescriptor,QObject *parent)
    :QThread(parent),socketdescriptor(socketdescriptor)
{

}


void WriteThread::run(){ //多线程执行的函数
    //QTcpSocket* tcp =new QTcpSocket;    持久化连接
   {
        QTcpSocket tcp2; //离开作用域自动释放这条新连接
        QTcpSocket* tcp =& tcp2;
        if(!tcp->setSocketDescriptor(socketdescriptor)){
            emit myerror(tcp->error());  //触发自定义的error信号
            return;
        }
        qDebug()<<"run()";
        QByteArray data;
        QDataStream out(&data,QIODevice::WriteOnly);
        out.setVersion(QDataStream::Qt_5_12);

        tcp->write(data);

    }
    //tcp->disconnectFromHost(); //主动断开与远程主机的TCP连接。
}

主逻辑类

主要实现按钮开启和关闭服务器

#include "dialog.h"
#include "ui_dialog.h"
#include<QMessageBox>
Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);
     setWindowTitle("连接计数器服务端");
    ui->server_ip->setText("127.0.0.1");
    ui->server_port->setText("8888");
    icount= 0;
    tcpserver=new TcpNewConnet(this);


}

Dialog::~Dialog()
{
    delete ui;
}


void Dialog::slotsdispFunc(){
    ui->currentv->setText(tr("客户端请求%1次").arg(++icount));
}

void Dialog::on_close_clicked()
{
        //先关闭所有socket
       if(!tcpserver){
           tcpserver->disconnect(); //用于断开 QTcpSocket 对象的所有信号与槽的连接。
           tcpserver->close();      //它会向对端发送 FIN 数据包,并等待对端的确认,完成 TCP 连接的正常关闭过程。
           //fin回调 已调用 tcpSocket->deleteLater(); //它不会立即删除对象,而是将其标记为待删除状态,等到当前事件循环结束后再执行删除操作。

       }
       if(tcpserver->isListening())
       {
           tcpserver->close();
            //不调用 deleteLater 为了下次再次开启
           ui->listen->setEnabled(true);
           ui->close->setEnabled(false);
           QMessageBox::critical(this,tr("提示"),
                                 tr("多线程服务器已关闭"));
       }


}

void Dialog::on_listen_clicked()
{
    QString ip(ui->server_ip->text());
    uint16_t port =ui->server_port->text().toUInt();
    if(!tcpserver->listen(QHostAddress(ip),port)){

        tcpserver->close();QMessageBox::critical(this,tr("提示"),
                                                 tr("多线程服务器已关闭"));
        return;
    }
    QMessageBox::information(this,tr("提示"),tr("多线程服务器已经启动"));
    ui->listen->setEnabled(false);
    ui->close->setEnabled(true);
}

总结

通过继承重写和信号槽的方式,可以实现连接建立,断开,发送前,发送后等等操作绑定,重写需要去找指定的重写函数,而信号去找指定的信号名。信号槽机制当绑定多个的时候,是按照绑定的顺序执行,因为底层是信号队列,保证顺序。

如果对信号槽有兴趣,可以看我之前发布的qt 多线程和网络编程文章。

最后附上源代码链接
对您有帮助的话,帮忙点个star

 41-clinet-count · jbjnb/Qt demo - 码云 - 开源中国 (gitee.com)

41-server-count · jbjnb/Qt demo - 码云 - 开源中国 (gitee.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/789327.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

启动tomcat时提示The JRE_HOME environment variable is not defined correctly

我的情况是在已经安装过jdk后&#xff0c;启动tomcat时出现以下问题 原因是环境变量配置不正确导致的 首先确认一下jre的实际安装路径 然后修改环境变量配置文件 vim /etc/profile 添加以下内容&#xff0c;JRE_HOME为实际jre的路径 然后保存退出 让文件生效一下 source…

Docker-搭建部署Jenkins(保姆篇)

文章目录 Jenkins部署拉取镜像启动容器查看初始密码关闭CSRF Jenkins页面使用解决插件下载缓慢访问jenkins页面推荐插件安装创建一个管理员账号实例配置页面展示 更多相关内容可查看 Jenkins部署 拉取镜像 如果想拉取对应版本请指明版本号 docker pull jenkins/jenkins:lts-…

数据分析入门指南:表结构数据(三)

在数字化转型的浪潮中&#xff0c;表结构数据作为企业决策支持系统的核心要素&#xff0c;其重要性日益凸显。本文深入剖析了表结构数据的本质特征、高效处理策略&#xff0c;并探讨了其在现代商业智能环境中的广泛应用&#xff0c;旨在为数据分析师与决策者提供前沿洞察与实战…

电脑屏幕亮度怎么调?3个技巧,指尖轻松调控明亮度

你是否曾因为屏幕亮度的不合适而感到眼睛疲劳&#xff1f;是否曾在深夜加班时&#xff0c;被电脑屏幕刺眼的亮度搅得心烦意乱&#xff1f;电脑屏幕亮度怎么调呢&#xff1f;本文将为你介绍3个简便易行的技巧&#xff0c;让指尖轻松掌控屏幕亮度&#xff0c;享受舒适的观看体验。…

前端vue 实现取色板 的选择

大概就是这样的 一般的web端框架 都有自带的 的 比如 ant-design t-design 等 前端框架 都是带有这个的 如果遇到没有的我们可以自己尝试开发一下 简单 的 肯定比不上人家的 但是能用 能看 说的过去 我直接上代码了 其实这个取色板 就是一个input type 是color 的input …

Vue组件通信props和$emit用法

父传子&#xff0c;通过props 子传父&#xff0c;通过$emit App.vue <template><div class"app" style"border: 3px solid #000; margin: 10px">我是APP组件<!-- 1.给组件标签&#xff0c;添加属性方式 赋值 --><!-- 添加属性传值 …

untiy 在菜单栏添加自定义按钮 点击按钮弹出一个Unity窗口,并在窗口里添加属性

using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.Rendering.PostProcessing;public class AutoGenerateWindow : EditorWindow //这是定义一个窗口 {public string subjecttName "科目名字";//科目的名字public GameOb…

补光灯LED照明 2.7V4.2V5V升60V80V100V升压恒流芯片IC-H6902B

H6902B升压恒流芯片IC确实是一款为LED照明应用设计的稳定且可靠的解决方案。这款芯片具有以下几个显著特点&#xff1a; 高效率&#xff1a;效率高达95%以上&#xff0c;这意味着在驱动LED灯时&#xff0c;电源到LED的能量转换效率非常高&#xff0c;减少了能量损失&#xff0…

抖音本地生活服务商怎么申请?附详细教程!

随着本地生活的发展潜力和行业前景的不断展现&#xff0c;本地生活服务商也逐渐成为了一大热门职业。在此背景下&#xff0c;作为拥有约8亿日活用户的抖音成为了人们选择平台时的优先考虑对象&#xff0c;而以抖音本地生活服务商怎么申请为代表的相关问题也因此在多个创业者群中…

雪花算法改造失败导致ID重复问题分享

背景 雪花算法是分布式应用中应用比较多的 ID 生成算法&#xff0c;某项目中使用该算法生成ID&#xff0c;近期被反馈算法生成的 ID 存在重复的情况&#xff0c;排了一天&#xff0c;终于找到问题根源了。 本文将总结这个 Bug &#xff0c;顺便温故一下雪花算法及改造雪花算法…

mes系统在新材料行业中的应用价值

万界星空科技新材料MES系统是针对新材料制造行业的特定需求而设计的制造执行系统&#xff0c;它集成了生产计划、过程监控、质量管理、设备管理、库存管理等多个功能模块&#xff0c;以支持新材料生产的高效、稳定和可控。以下是新材料MES系统的具体功能介绍&#xff1a; 一、生…

创建 ComfyUI 自定义节点的基本指南

ComfyUI 自定义节点基础教程 开始前的准备理解 ComfyUI 节点创建自定义节点1. 定义节点参数2. 实现节点逻辑3. 与 ComfyUI 集成 测试和改进节点结论 ComfyUI 是一个多功能的Stable Diffusion图像/视频生成工具&#xff0c;能够让开发者设计并实现自定义节点&#xff0c;扩展功能…

无线领夹麦克风哪个牌子好,揭秘降噪领夹麦排行榜内幕!

在当今这个短视频如潮水般涌动的时代&#xff0c;人们的日常生活中掀起了一股新的潮流——用Vlog来捕捉生活的点点滴滴&#xff0c;许多博主在各种短视频和直播平台上开启了他们的副业之旅。这一现象催生了麦克风技术的飞速进步&#xff0c;使其从单一的录音工具转变为拥有多种…

私域运营从0到1冷启动

私域社群的冷启动是一个从无到有的过程&#xff0c;需要策略和耐心来吸引并维护用户。以下是一些步骤和策略&#xff0c;可以帮助你的私域社群实现从0到1的冷启动&#xff1a; 1. **明确目标和定位**&#xff1a; - 确定社群的目标用户和他们的需求。 - 明确社群的主题和…

一文清晰了解CSS——简单实例

首先一个小技巧&#xff1a; 一定要学会的vsCode格式化整理代码的快捷键&#xff0c;再也不用手动调格式了-腾讯云开发者社区-腾讯云 (tencent.com) CSS选择器用于选择要应用样式的HTML元素。常见的选择器包括&#xff1a; 类选择器&#xff1a;以.开头&#xff0c;用于选择具…

多个标签页中复用同一 QTableView

在 PyQt 中实现在多个标签页中复用同一个 QTableView 实例&#xff0c;复用同一个 QTableView 实例可以减少内存和资源的使用。每个 QTableView 实例都会消耗一定的内存和处理资源&#xff0c;如果每个标签页都创建一个新的实例&#xff0c;会增加系统的负担。通过复用实例&…

Hi3861鸿蒙开发环境搭建

1.1 安装配置Visual Studio Code 打开Download Visual Studio Code - Mac, Linux, Windows选择下载安装Windows系统的Visual Studio Code。 下载后进行安装。Visual Studio Code安装完成后&#xff0c;通过内置的插件市场搜索并安装开发所需的插件如图所示&#xff1a; 1.2 安…

2024 年最佳 Figma 字体

字体不仅仅是文本字符&#xff0c;它们还塑造了用户体验。从引导用户浏览界面到传达品牌个性&#xff0c;字体对于设计​​至关重要。然而&#xff0c;找到适合您的网站或应用风格的完美字体可能具有挑战性。 但不要害怕&#xff0c;我们会帮助您&#xff01;请继续关注&#x…

技术成神之路:设计模式(四)工厂方法模式

1.定义 工厂方法模式&#xff08;Factory Method Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一种创建对象的接口&#xff0c;而不是通过具体类来实例化对象。工厂方法模式的主要作用是让子类决定实例化哪一个类&#xff0c;从而实现对象创建的延迟到具体子类…

EE trade:千足金是什么意思

千足金(也称足金999、足999、au999等)是一种金含量不低于999‰的黄金&#xff0c;这意味着在一千克的千足金中&#xff0c;至少有999克是纯金。由于其极高的纯度&#xff0c;千足金在市场上比普通的足金价格略高&#xff0c;虽然价格差距可能仅为每克几元&#xff0c;但在大批量…