带你0到1之QT编程:十八、最简单之TCP协议工作原理及实战编程

此为QT编程的第十八谈!关注我,带你快速学习QT编程的学习路线

每一篇的技术点都是很很重要!很重要!很重要!但不冗余!

我们通常采取总-分-总和生活化的讲解方式来阐述一个知识点!

码农不易,各位学者学到东西请点赞支持支持

开始部分:

总:此次实战主要是实现一个客户端,一个服务端,来了解TCP通信的过程。

分:

一、客户端的实现

1.老规矩,创建一个QMainWindow项目

2.先在.ui文件布局好

3.在.h引入相关头文件

4.在.h文件声明一个客户端专属的socket,相当于电话机,用来通信服务器

5.再声明closeEvent事件,相当于电话机挂号,断开服务器的通信

6.再声明连接函数、断开连接函数、发送消息槽函数的基本功能,再添加一个获取ip地址函数

7.声明完成,就在.cpp进行实现了,首先创建专属的电话机,客户端socket

8.首先实现QComboBox获取本机ip地址的一个功能,就要先实现getlocalip()功能

9.将获取到的ip地址存入QComboBox里面

10.实现连接函数、断开连接函数、发送消息槽函数的基本功能

11.连接信号与槽,当socket连接和断开连接和收到数据的时候触发这些槽函数

12.三个按钮的槽函数实现

13.再将关闭事件实现

14.基础的功能已经完美实现了!发送消息,接收消息,连接,断开连接四个主要的功能,通关qt的信号与槽机制完美实现!

15.需要通过与服务器进行连接检测,检测成功!

二、服务端的实现

1.创建QMainWindow一个项目

2.在.ui布局添加相关控件

3.在.pro添加配置,在.h文件添加相关头文件

4..h文件声明一个QTcpServer对象和一个QTcpSocket对象

5.声明函数和槽函数还有关闭事件

6.先实现四个服务器的基础功能,客户端连接,客户端断开,读取数据,发送数据功能

7.创建一个新连接的槽函数,当有新连接的时候就调用

8.再实现剩下的按钮槽函数

9.实现关闭事件

10.实现最主要的自定义函数来获取本地ip地址

11.在构造函数创建对象和连接槽

12.实现效果如下:

总:无论是客户端还是服务端,实现的基础功能都是四个,建立连接,断开连接,发送数据,接收数据。

客户端的参考源码:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //客户端专属socket
    tcpclient=new QTcpSocket(this);

    QString strip=getlocalip();

    ui->comboBox_ip->addItem(strip);

    connect(tcpclient,SIGNAL(connected()),this,SLOT(connectfunc()));
    connect(tcpclient,SIGNAL(disconnected()),this,SLOT(disconnectfunc()));
    connect(tcpclient,SIGNAL(readyRead()),this,SLOT(socketreaddata()));
}

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

QString MainWindow::getlocalip()//获取本机ip地址
{
    QString hostname=QHostInfo::localHostName();//获取本地主机名
    QHostInfo hostinfo=QHostInfo::fromName(hostname);//通过主机名获取主机信息

    QString localip="";

    QList<QHostAddress>addlist=hostinfo.addresses();//获取本机的所有ip地址

    if(!addlist.isEmpty())
    {
        for(int i=0;i<addlist.count();i++)
        {
            QHostAddress ahost=addlist.at(i);
            if(QAbstractSocket::IPv4Protocol==ahost.protocol())
            {
                localip=ahost.toString();
                break;
            }
        }
    }
    return localip;
}

void MainWindow::connectfunc()//连接
{
    ui->plainTextEdit_Show->appendPlainText("*********已经连接到服务器端**********");
    ui->plainTextEdit_Show->appendPlainText("************peer address:"+tcpclient->peerAddress().toString());
    ui->plainTextEdit_Show->appendPlainText("************peer port:"+QString::number(tcpclient->peerPort()));
    ui->pushButton_connect->setEnabled(false);
    ui->pushButton_quit->setEnabled(true);
}

void MainWindow::disconnectfunc()//断开连接
{
    ui->plainTextEdit_Show->appendPlainText("************已断开服务端的连接************");
    ui->pushButton_connect->setEnabled(true);
    ui->pushButton_quit->setEnabled(false);
}

void MainWindow::socketreaddata()//读取信息
{
    while(tcpclient->canReadLine())//检查是否有完整的行数据
        ui->plainTextEdit_Show->appendPlainText("输入:"+tcpclient->readLine());
}

void MainWindow::on_pushButton_connect_clicked()//连接服务
{
    QString addr=ui->comboBox_ip->currentText();
    quint16 port=ui->spinBox_port->value();
    tcpclient->connectToHost(addr,port);
}

void MainWindow::on_pushButton_quit_clicked()//停止服务
{
    if(tcpclient->state()==QAbstractSocket::ConnectedState)
        tcpclient->disconnectFromHost();
}

void MainWindow::on_pushButton_send_clicked()//发送消息
{
    QString strmsg=ui->lineEdit_Msg->text();
    ui->plainTextEdit_Show->appendPlainText("输出:"+strmsg);
    ui->lineEdit_Msg->clear();

    QByteArray str=strmsg.toUtf8();
    str.append("\n");
    tcpclient->write(str);//发送数据给服务端
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if(tcpclient->state()==QAbstractSocket::ConnectedState)
    {
        tcpclient->disconnectFromHost();//断开与服务器的连接
    }
    event->accept();
}

服务端的参考源码:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QString strip=GetLocalIpAddress();

    ui->comboBoxIp->addItem(strip);

    tcpserver=new QTcpServer(this);

    connect(tcpserver,SIGNAL(newConnection()),this,SLOT(newconnection()));//存放了基础功能的信号与槽

}

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


void MainWindow::on_pushButton_Start_clicked()//开始服务
{
    QString ip=ui->comboBoxIp->currentText();
    quint16 port=ui->spinBoxPort->value();

    QHostAddress address(ip);
    tcpserver->listen(address,port);

    ui->plainTextEdit_DispMsg->appendPlainText("$$$$$$$$$$开始监听$$$$$$$$$$");
    ui->plainTextEdit_DispMsg->appendPlainText("$$$$$$$$$$服务器地址$$$$$$$$$$:"+
                                               tcpserver->serverAddress().toString());
    ui->plainTextEdit_DispMsg->appendPlainText("$$$$$$$$$$服务器端口$$$$$$$$$$:"+
                                               QString::number(tcpserver->serverPort()));
    ui->pushButton_Start->setEnabled(false);
    ui->pushButton_Stop->setEnabled(true);

}

void MainWindow::on_pushButton_Stop_clicked()//停止服务
{
    if(tcpserver->isListening())
    {
        tcpserver->close();


        tcpsocket->disconnect(); // 加上该关闭套接,服务器停止后,再也无法收到客户端的消息


        ui->pushButton_Start->setEnabled(true);
        ui->pushButton_Stop->setEnabled(false);
    }

}

void MainWindow::on_pushButton_Send_clicked()//发送数据
{
    QString strmsg=ui->lineEdit_InputMsg->text();
    ui->plainTextEdit_DispMsg->appendPlainText("[out]:"+strmsg);

    ui->lineEdit_InputMsg->clear();

    QByteArray str=strmsg.toUtf8();
    str.append("\n");
    tcpsocket->write(str);
}


QString MainWindow::GetLocalIpAddress() // 获取本机的IP地址
{
    QString hostname=QHostInfo::localHostName();
    QHostInfo hostinfo=QHostInfo::fromName(hostname);

    QString localip="";

    QList<QHostAddress> addresslist=hostinfo.addresses();

    if(!addresslist.isEmpty())
    {
        for (int i=0;i<addresslist.count();i++)
        {
            QHostAddress addrhost=addresslist.at(i);
            if(QAbstractSocket::IPv4Protocol==addrhost.protocol())
            {
                localip=addrhost.toString();
                break;
            }

        }
    }

    return localip;
}

void MainWindow::clientconnect()
{
    // 客户端连接
    ui->plainTextEdit_DispMsg->appendPlainText("**********客户端socket连接**********");
    ui->plainTextEdit_DispMsg->appendPlainText("**********peer address:"+
                                               tcpsocket->peerAddress().toString());
    ui->plainTextEdit_DispMsg->appendPlainText("**********peer port:"+
                                               QString::number(tcpsocket->peerPort()));

}

void MainWindow::clientdisconnect()
{
    // 客户端断开连接
    ui->plainTextEdit_DispMsg->appendPlainText("**********客户端socket断开连接**********");
    tcpsocket->deleteLater();

}

void MainWindow::socketreaddata()
{
    // 读取数据
    while(tcpsocket->canReadLine())
        ui->plainTextEdit_DispMsg->appendPlainText("[in]"+tcpsocket->readLine());

}

void MainWindow::newconnection()//存放各种信号与槽
{
    tcpsocket=tcpserver->nextPendingConnection();

    connect(tcpsocket,SIGNAL(connected()),this,SLOT(clientconnect()));
    clientconnect();

    connect(tcpsocket,SIGNAL(disconnected()),this,SLOT(clientdisconnect()));

    connect(tcpsocket,SIGNAL(readyRead()),this,SLOT(socketreaddata()));



}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if(tcpserver->isListening())
        tcpserver->close();

    event->accept();
}

  学习链接:此https://xxetb.xetslk.com/s/3Kif2D

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

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

相关文章

OpenCV运动分析和目标跟踪(3)计算图像序列的加权平均值函数accumulateWeighted()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 更新一个运行平均值。 该函数计算输入图像 src 和累积器 dst 的加权和&#xff0c;使得 dst 成为帧序列的运行平均值&#xff1a; dst ( x , y…

git使用“保姆级”教程1——简介及配置项设置

一、git介绍 Git是一个开源的分布式版本控制系统&#xff0c;用于&#xff1a;敏捷高效地处理任何或小或大的项目。Git 是Linus Torvalds 为了帮助管理Linux内核开发而开发的一个开放源码的版本控制软件。版本控制&#xff1a; 版本控制&#xff08;Revision control&#xff…

《概率论与数理统计》学渣笔记

文章目录 1 随机事件和概率1.1 古典概型求概率随机分配问题简单随机抽样问题 1.2 几何概型求概率1.3 重要公式求概率 2 一维随机变量及其分布2.1 随机变量及其分布函数的定义离散型随机变量及其概率分布&#xff08;概率分布&#xff09;连续型随机变量及其概率分布&#xff08…

【MYSQL】聚合查询、分组查询、联合查询

目录 聚合查询聚合函数count()sum()avg()max()和min()总结 分组查询group by 子句having 子句 联合查询笛卡尔积内连接外连接自连接子查询单行子查询多行子查询from子句使用子查询 合并查询 聚合查询 聚合查询就是针对表中行与行之间的查询。 聚合函数 count() count(列名)&a…

计算机网络笔记002

### 课堂讨论对话 **学生A**: 老师&#xff0c;计算机网络的组成是怎样的&#xff1f;&#x1f914; **老师**: 非常好的问题&#xff01;计算机网络主要由硬件、软件和通信协议三部分组成。我们先从硬件开始讨论吧。 **学生B**: 硬件包括哪些设备呢&#xff1f;&#x1f60…

【案例分享】智慧工地以及档案资料电子化

汇匠源分别在2020年和2023年与中国电建昆明院进行了项目合作&#xff0c;其中包括智慧工地的信息管理平台建设、数据录入、接口研发等&#xff1b;档案资料电子化的施工过程资料整理、归档等工作。 智慧工地 — 项目概况 — 项目名称&#xff1a;某JR项目智慧工地信息管理…

DriveMatriX Highway Dataset :高速公路驾驶数据集(猫脸码客 第196期)

DriveMatriX Highway Dataset 1.0&#xff1a;自动驾驶与ADAS感知验证的里程碑 在当今快速发展的自动驾驶&#xff08;AV&#xff09;和高级驾驶辅助系统&#xff08;ADAS&#xff09;领域&#xff0c;数据的获取与处理成为了推动技术进步的关键因素。为了在这些复杂且多变的交…

Allegro第二季度GMV增长11.1%,活跃买家突破2000万

9月19日&#xff0c;波兰电商巨头Allegro公布了2024年第二季度财报。第二季度&#xff0c;Allegro的商品交易总额&#xff08;GMV&#xff09;同比增长11.1%&#xff0c;调整后EBITDA同比增长31.5%&#xff0c;均好于预期。 财报显示&#xff0c;Allegro各区域活跃买家数量超过…

java日志框架之Log4j

文章目录 一、Log4j简介二、Log4j组件介绍1、Loggers (日志记录器)2、Appenders&#xff08;输出控制器&#xff09;3、Layout&#xff08;日志格式化器&#xff09; 三、Log4j快速入门四、Log4j自定义配置文件输出日志1、输出到控制台2、输出到文件3、输出到数据库 五、Log4j自…

学习记录:js算法(四十二): 寻找两个正序数组的中位数

文章目录 寻找两个正序数组的中位数我的思路网上思路 总结 寻找两个正序数组的中位数 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,3], n…

Transformer推理结构简析(Decoder + MHA)

一、Transformer 基本结构 Transformer由encoder和decoder组成&#xff0c;其中&#xff1a; encoder主要负责理解&#xff08;understanding&#xff09; The encoder’s role is to generate a rich representation (embedding) of the input sequence, which the decoder c…

【深度学习】(5)--搭建卷积神经网络

文章目录 搭建卷积神经网络一、数据预处理1. 下载数据集2. 创建DataLoader&#xff08;数据加载器&#xff09; 二、搭建神经网络三、训练数据四、优化模型 总结 搭建卷积神经网络 一、数据预处理 1. 下载数据集 在PyTorch中&#xff0c;有许多封装了很多与图像相关的模型、…

Java/Spring项目的包开头为什么是com?

Java/Spring项目的包开头为什么是com&#xff1f; 下面是一个使用Maven构建的项目初始结构 src/main/java/ --> Java 源代码com.example/ --->为什么这里是com开头resources/ --> 资源文件 (配置、静态文件等)test/java/ --> 测试代码resourc…

Visual Studio-X64汇编编写

纯64位汇编&#xff1a; includelib ucrt.lib includelib legacy_stdio_definitions.lib includelib user32.libextern printf:proc extern MessageBoxA:proc.data szFormat db "%s",0 szHello db "HelloWorld",0 szRk db "123",0.code start p…

无线安全(WiFi)

免责声明:本文仅做分享!!! 目录 WEP简介 WPA简介 安全类型 密钥交换 PMK PTK 4次握手 WPA攻击原理 网卡选购 攻击姿态 1-暴力破解 脚本工具 字典 2-Airgeddon 破解 3-KRACK漏洞 4-Rough AP 攻击 5-wifi钓鱼 6-wifite 其他 WEP简介 WEP是WiredEquivalentPri…

百度智能云API调用

植物识别API import base64 import urllib import requestsAPI_KEY "你的图像识别API_KEY" SECRET_KEY "你的图像识别SECRET_KEY"def main():url "https://aip.baidubce.com/rest/2.0/image-classify/v1/plant?access_token" get_access_t…

24/9/19 算法笔记 kaggle BankChurn数据分类

题目是要预测银行里什么样的客户会流失&#xff0c;流失的概率是多少 我这边先展示一下我写的二分类的算法 import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.linear_model impo…

60.【C语言】内存函数(memset,memcmp函数)

3.memset函数(常用) *简单使用 memset:memory set cplusplus的介绍 点我跳转 翻译: 函数 memset void * memset ( void * ptr, int value, size_t num ); 填充内存块 将ptr指向的内存块的前num个字节设置为指定值&#xff08;解释为无符号char&#xff09;。 (指针ptr类型为…

qt-C++笔记之作用等同的宏和关键字

qt-C笔记之作用等同的宏和关键字 code review! Q_SLOT 和 slots&#xff1a; Q_SLOT是slots的替代宏&#xff0c;用于声明槽函数。 Q_SIGNAL 和 signals&#xff1a; Q_SIGNAL类似于signals&#xff0c;用于声明信号。 Q_EMIT 和 emit&#xff1a; Q_EMIT 是 Qt 中用于发射…

【Linux】Linux的基本指令(1)

A clown is always a clown.&#x1f493;&#x1f493;&#x1f493; 目录 ✨说在前面 &#x1f34b;知识点一&#xff1a;Linux的背景 •&#x1f330;1.Unix发展的历史 •&#x1f330;2.Linux发展历史 •&#x1f330;3.企业应用现状 •&#x1f330;4.发行版本 &…