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()
{//先关闭所有socketif(!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)

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

从零开始做题:MP3

题目 给出一个mp3文件 解题 右键->selection->save selection->另存为xxx.png即可 8750d5109208213f E:\逐鹿\MISC\tools\MP3Stego_1_1_19\MP3Stego>.\decode -X cipher.mp3 MP3StegoEncoder 1.1.19 See README file for copyright info Input file cipher.mp3…

秒懂设计模式--学习笔记(8)【结构型-组合模式】

目录 7、组合模式7.1 组合模式&#xff08;Composite&#xff09;7.2 叉树结构7.3 文件系统7.4 目录树展示7.5 自相似性的涌现7.6 组合模式的各角色定义7.7 组合 7、组合模式 7.1 组合模式&#xff08;Composite&#xff09; 是针对由多个节点对象&#xff08;部分&#xff0…

centos部署jar包

第一步&#xff1a; 将IDEA中的项目打包为jar,将这个jar文件放到centos服务器上的目录里&#xff0c;我在opt新建api目录&#xff0c;将jar文件放入&#xff0c;如下图&#xff1a; 第二步&#xff1a; 将需要读取的配置文件也放入此目录(其他目录也可以&#xff0c;和脚本中…

Thread类的start()方法和run()方法的区别

在Java多线程编程中&#xff0c;Thread类是一个非常重要的类&#xff0c;它提供了创建和管理线程的能力。对于初学者来说&#xff0c;理解Thread类的start()方法和run()方法之间的区别尤为重要。本文将深入探讨这两者之间的不同&#xff0c;帮助读者更好地掌握Java多线程编程的…

web端的vscode编辑器

下载code-server到本地 略 参考 https://blog.csdn.net/kfashfasf/article/details/137110668 运行code-server 到用户目录下设置 vim ~/.config/code-server/config.yaml . bind-addr: 0.0.0.0:8080 auth: password password: xxxxxx cert: false运行 [centosamazon22 ~…

中职网络安全wire0077数据包分析

从靶机服务器的FTP上下载wire0077.pcap&#xff0c;分析该文件&#xff0c;找出黑客入侵使用的协议&#xff0c;提交协议名称 SMTP 分析该文件&#xff0c;找出黑客入侵获取的zip压缩包&#xff0c;提交压缩包文件名 DESKTOP-M1JC4XX_2020_09_24_22_43_12.zip 分析该文件&…

使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-滚动背景(四)

文章目录 开发思路开发思路 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击&#xff08;一&#xff09; 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-激光组件&#xff08;二&#xff09; 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-飞船动画&#xff08…

pytorch-RNN实战-正弦曲线预测

目录 1. 正弦数据生成2. 构建网络3. 训练4. 预测5. 完整代码6. 结果展示 1. 正弦数据生成 曲线如下图&#xff1a; 代码如下图&#xff1a; 50个点构成一个正弦曲线随机生成一个0~3之间的一个值&#xff08;随机的原因是防止每次都从相同的点开始&#xff0c;50个点的正弦曲…

JavaSE 面向对象程序设计进阶 IO流 字节流详解 抛出异常

input output 像水流一样读取数据 存储和读取数据的解决方案 内存中数据不能永久化存储 程序停止运行 数据消失 File只能对文件本身进行操作 不能读写文件里存储的数据 读写数据必须要有IO流 可以把程序中的数据保存到文件当中 还可以把本地文件中的数据读取到数据当中 分…

白酒营销策划全攻略:从市场调研到执行落地的实战指南!

为白酒品牌做营销策划&#xff0c;那可得像给自家的孩子挑衣服一样&#xff0c;得量身定制&#xff0c;得考虑孩子的身材、喜好&#xff0c;还得看看衣服的款式和布料。 这里可以分享一点自己多年的实战干货给你&#xff0c;希望对你有所帮助。 首先&#xff0c;得做好“侦查…

【常见开源库的二次开发】一文学懂CJSON

简介&#xff1a; JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式。它基于JavaScript的一个子集&#xff0c;但是JSON是独立于语言的&#xff0c;这意味着尽管JSON是由JavaScript语法衍生出来的&#xff0c;它可以被任何编程语言读取和生成…

CentOS7系统上安装MySQL8.0(rpm-bundle.tar)详细过程

一、MySQL官网下载安装包 1.进入官网MySQL :: Download MySQL Community Server 2.查看自己的版本和架构 uname -mcat /etc/redhat-release 3.选择对应版本并下载 4.查看linux自带的mariadb数据库&#xff0c;有就卸载掉。 rpm -qa | grep mariadbrpm -e mariadb-libs…

【卡尔曼滤波】高斯白噪声

生成高斯白噪声并将其应用于信号处理 生成高斯白噪声并将其应用于信号处理 #以下是一个生成高斯白噪声并将其应用于信号处理的示例代码:import numpy as np import matplotlib.pyplot as plt import matplotlib.font_manager ## not work#notice matplotlibrc is a file, not…

学生选课管理系统(Java+MySQL)

技术栈 Java: 用于实现系统的核心业务逻辑。MySQL: 作为关系型数据库&#xff0c;用于存储系统中的数据。JDBC: 用于Java程序与MySQL数据库之间的连接和交互。Swing GUI: 用于创建图形用户界面&#xff0c;提升用户体验。 系统功能 我们的学生选课管理系统主要针对学生和管理…

突破传统:实现智慧校园实习单位变更

在智慧校园的实习管理系统设计中&#xff0c;充分考虑到了实习阶段学生可能遇到的实际需求&#xff0c;特别是实习单位变更这一灵活性要求&#xff0c;系统特设了一套完善的在线处理机制&#xff0c;旨在促进学生、学校与企业间的顺畅沟通与协调&#xff0c;确保实习过程的平稳…

Gmail邮件提醒通知如何设置?有哪些方法?

Gmail邮件提醒通知功能怎么样&#xff1f;通知邮件怎么有效发送&#xff1f; Gmail作为全球广泛使用的电子邮件服务&#xff0c;提供了多种邮件提醒通知功能&#xff0c;帮助用户不错过重要信息。AokSend将详细介绍如何设置Gmail邮件提醒通知&#xff0c;确保您不会错过任何重…

IT审计必看!对比旧版,CISA考试改版升级亮点和重点内容是什么?

官方通知&#xff0c;今年8月1日&#xff0c;CISA新版考纲正式上线&#xff0c;旧版在7月23日后就无法约考了。 艾威培训邀请了国内知名的IT审计CISA授课老师吴老师来为大家详细讲解CISA新版考纲的变化 目前第28th版教材只有英文版&#xff0c;中文版尚未发布。我们艾威经验丰…

【NOI-题解】1108 - 正整数N转换成一个二进制数1290 - 二进制转换十进制1386 - 小丽找半个回文数1405 - 小丽找潜在的素数?

文章目录 一、前言二、问题问题&#xff1a;1108 - 正整数N转换成一个二进制数问题&#xff1a;1290 - 二进制转换十进制问题&#xff1a;1386 - 小丽找半个回文数问题&#xff1a;1405 - 小丽找潜在的素数&#xff1f; 三、感谢 一、前言 本章节主要对进制转换的题目进行讲解…

【UNI-APP】阿里NLS一句话听写typescript模块

阿里提供的demo代码都是javascript&#xff0c;自己捏个轮子。参考着自己写了一个阿里巴巴一句话听写Nls的typescript模块。VUE3的组合式API形式 startClient&#xff1a;开始听写&#xff0c;注意下一步要尽快开启识别和传数据&#xff0c;否则6秒后会关闭 startRecognition…

javascript高级部分笔记

javascript高级部分 Function方法 与 函数式编程 call 语法&#xff1a;call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 定义&#xff1a;调用一个对象的一个方法&#xff0c;以另一个对象替换当前对象。 说明&#xff1a;call 方法可以用来代替另一个对象调用一个方法。cal…