DLUT-2022 小学期每日进程

DLUT-2022 小学期每日进程

8.8

数据结构意义和应用

数据结构,简单来说就是研究数据的存储方式。在编写代码的过程中,我们进行数据存储的目的就是方便后期对数据的再利用,没有理由的数据存储行为是对存储空间管理的不负责。理解数据结构,可以帮助我们解决具有复杂关系的大量数据的存储问题。

不仅如此,数据结构还是算法的基石,为算法的实现提供坚实的基础。

那么数据结构有哪些组成方式呢?

  1. 线性结构

    线性结构是最简单的数据结构,包括数组、链表,以及它们衍生出的栈、队列、哈希表。

  2. 树是相对复杂的数据结构,其中比较有代表性的是二叉树,由它又衍生出了二叉堆之类的数据结构。

  3. 图是相对复杂的数据结构,因为在图中会呈现出多对多的关联关系。

单链表的基本概念和操作

在开始小学期之前,笔者已经尝试利用 Java 实现单链表、双向链表、循环链表,虽然对使用 c++ 实现没有涉及,但是能够更好地理解链表的运行原理,编程工具不同但是思想相同。

基本概念

链表(linked list)是一种在物理上非连续、非顺序的数据结构,由若干个节点(node)所组成。

单链表也就是单向链表,它的每一个节点包含两部分,一部分是存储数据的变量,另一部分是指向下一个节点的指针 next。链表的第 1 个节点被称为头节点,最后 1 个节点称为尾节点,尾节点的 next 指针指向 NULL。

与数组按照下标来随机寻找元素不同,对于链表的其中一个节点 myNode1 ,只能根据节点 myNode 的 next 指针来寻找到该节点的下一个节点 myNode2,依次向下查找,一级一级单向传递。

基本操作

以解决约瑟夫问题来举例

  • 初始化链表

    //定义节点
    class node {
       public:
        int data;
        node* next;  //下一个节点
    };
    
    //定义链表
    class list {
       public:
        int size;
        node* head;  //头节点地址
    };
    
    //初始化
    list* InitializeList() {
        list* List = new list;
        List->size = 0;
        List->head = new node;
        List->head->data = 0;
        List->head->next = List->head;
        return List;
    }
    
  • 插入数据和删除数据

    //插入数据
    void InsertList(list* List, int position, int num) {
        node* newNode = new node;
        newNode->data = num;
        newNode->next = NULL;
        //当前节点
        node* currentNode = List->head;
        for (int i = 0; i < position; i++) {
            currentNode = currentNode->next;
        }
        newNode->next = currentNode->next;
        currentNode->next = newNode;
        List->size++;
    }
    
    //删除数据,如果成功删除返回 true,空链表返回 false
    bool DeleteList(list* List, int num) {
        if (List->head == NULL) {
            return 0;
        }
    
        else {
            node* currentNode = List->head->next;
            int position = 0;
            for (int i = 0; i < List->size; i++) {
                if (currentNode->data == num)
                    break;
                currentNode = currentNode->next;
                position++;
            }
            currentNode = List->head;
            for (int i = 0; i < position; i++) {
                currentNode = currentNode->next;
            }
            currentNode->next = currentNode->next->next;
            List->size--;
        }
        return 1;
    }
    
  • 链表输入

    //输出
    void PrintList(list* List, int num) {
        node* currentNode = List->head;
        for (int i = 0; i < num; i++) {
            if (currentNode == List->head)
                currentNode = currentNode->next;
            cout << currentNode->data << " ";
            currentNode = currentNode->next;
        }
        cout << endl;
    }
    
  • 最终代码实现

    #include <iostream>
    using namespace std;
    
    int main() {
        int m, n;
        int temp;
        cout << "输入数字数量:";
        cin >> m;
        cout << "每数到多少去除:";
        cin >> n;
        //初始化链表
        list* List = InitializeList();
        for (int i = 0; i < m; i++) {
            InsertList(List, i, i + 1);
        }
        //输出初始链表
        cout << "链表为:" << endl;
        PrintList(List, m);
        cout << endl;
        node* currentNode = List->head;
        int icounter = 1;
        while (List->size != 0) {
            for (int i = 0; i < 2; i++) {
                //排除头节点
                if (currentNode == List->head)
                    currentNode = currentNode->next;
                currentNode = currentNode->next;
                if (currentNode == List->head)
                    currentNode = currentNode->next;
            }
            temp = currentNode->data;
            if (DeleteList(List, currentNode->data)) {
                cout << "第" << icounter << "次删除的数字为:" << temp << endl;
            } else
                cout << "空列表删除失败!" << endl;
            currentNode = currentNode->next;
            icounter++;
        }
        return 0;
    }
    
    

8.9

OOP

OOP(Object Oriented Programming)既面向对象程序设计,本质上是以建立模型体现出来的抽象思维过程和面向对象的方法,其基本原则是计算机程序由单个能起到子程序作用的单元或对象组合而成。

OOP 达到了软件工程的三个主要目标:重用性、灵活性和扩展性,核心概念是类和对象。

OOP = 对象 + 类 + 继承 + 多态 + 消息

面向对象的三大特征是:封装、继承和多态。

STL

概述

STL(Standard Template Library)译为标准模板库或者泛型库,包含有大量的模板类和模板函数,是 C++ 提供的一个基础模板的集合,用于高效完成各种功能。

从根本上说,STL 是一些容器、算法和其他一些组件的集合,所有容器和算法都是总结了几十年来算法和数据结构的研究成果,汇集了许多计算机专家学者经验的基础上实现的,STL 基本上达到了各种存储方法和相关算法的高度优化。

STL 六大部件:容器(Containers)、分配器(Allocators)、算法(Algorithm)、迭代器(Iterators)、适配器(Adapters)、仿函数(Functors)。

STL 参考文档
常用STL

在 C++ 标准中,STL 被组织为以下的头文件:algorithm/deque/functional/iterator/list/map/memory/numeric/queue/set/stack/utility/vector

  • pair

    表示一个二元组或元素对,并提供按照字典序对元素进行大小比较。在 中定义了 pair 的六个比较运算符:<、>、<=、>=、==、!=,先比较 first ,再比较 second,也可以通过重载改变比较逻辑。

  • vector

    向量容器模板类,以连续数组的方式存储元素序列,可以看做是以顺序结构实现的线性表,是动态数组的理想选择,需要两个模板参数,第一个是存储元素的数据类型,第二个是参数存储分配器的类型。

    #include<vector>
    vector<int>s;//定义一个空 vector,存储 int 类型对象
    vector<int>s(n);//定义一个含有 n 个 int 元素的 vector 对象
    vector<int>s(first,last);//定义一个 vector 对象,并从由迭代器 first 和 last 定义的序列中复制初值
    	s[i];//直接以下标方式访问容器中的元素。
        s.front();//返回首元素。
        s.back();//返回尾元素。
        s.push_back(x);//向表尾插入元素 x。
        s.size();//返回表长。
        s.empty();//当表空时,返回真,否则返回假。
        s.pop_back();//删除表尾元素。
        s.begin();//返回指向首元素的随机存取迭代器。
        s.end();//返回指向尾元素的下一个位置的随机存取迭代器。
        s.insert(it, x);//向迭代器 it 指向的元素前插入新元素 val。
        s.insert(it, n, x);//向迭代器 it 指向的元素前插入 n 个 x。
      	s.insert(it, first, last);//将由迭代器 first 和 last 所指定的序列		[first, last)插入到迭代器 it 指向的元素前面。
        s.erase(it);//删除由迭代器 it 所指向的元素。
    	s.erase(first, last);//删除由迭代器 first 和 last 所指定的序列[first, last)。
        s.reserve(n);//预分配缓冲空间,使存储空间至少可容纳 n 个元素。
    	s.resize(n);//改变序列的长度,超出的元素将会被删除,如果序列需要扩展,原空间小于 n, 元素默认值将填满扩展出的空间。
    	s.resize(n, val);//改变序列的长度,超出的元素将会被删除,如果序列需要扩展,原空间小于 n, 将用 val 填满扩展出的空间。
    	s.clear();//删除容器中的所有的元素。 
    	s.swap(v);//将 s 与另一个 vector 对象 v 进行交换
    
  • iterator

    iterator 迭代器,是用于访问容器中元素的指示器,相当于数据结构中所说的“遍历指针”,也可以看成一种泛化的指针,STL 有一下几类迭代器:

    • 输入 iterator,在容器的连续区间内向前移动,读取容器内任意值
    • 输出 iterator,把值写进它所指向的容器中
    • 前向 iterator,读取队列中的值,并可以向前移动到下一位置(++p,p++)
    • 双向 iterator,读取队列中的值,并可以向前向后遍历容器
    • 随机访问 iterator,可以直接以下标的方式对容器进行访问
    • 流 iterator,可以直接输出、输入流中的值
  • string

    string 是 STL 为我们提供的更便捷的字符串的表达方式,可以看做是一个字符的 vector,vector 上的各种操作都适用于 string,还支持字符串的拼合、转换等操作。

  • stack/queue

    stack(栈) 和 queue(队列) 是常用的数据容器。

    • stack 定义在 中,有两个模板参数,一个是元素类型,一个是容器类型,前者是必要的。可以进行入栈、出栈、访问栈顶、判断栈空等操作。
    • queue 定义在 中,也是两个模板参数,第一个元素类型是必要的。可以进行入队、出队、访问队首元素、访问队尾元素、判断队列空、访问队列中的元素个数等操作。
  • map

    中定义了模板类 map 和 multimap,用有序二叉树来存储类型为 pair<const Key,T> 的元素对序列。map 中所有元素的 Key 都是唯一的,multimap 则允许有重复的 Key。这类容器也称为“关联容器”,可以通过一个 Key 快速确定一个元素,非常适合于需要按照 Key 查找元素的容器。map 模板类需要四个模板参数,分别是键值类型、元素类型、比较算子、分配器类型,其中键值类型和元素类型是必要的。

    map 的基本操作有:定义 map 对象、向 map 中插入元素对、查找元素对、删除元素对等。

  • algorithm

    是 STL 中最大的一个头文件,它是由一大堆模板函数组成的。

8.10

图形用户界面框架

图形用户界面(Graphical User Interface) 即 GUI,C++ 常用的 GUI 开发框架有以下几个:

  • QT

    QT 是跨平台 C++ 图形用户界面应用程序开发框架,目前使用广泛。

  • MFC

    Windows 下的 GUI 库,使用比较广泛。

  • wxWidgets

    wxWidgets 应用于 Windows、Linux、MacOS等平台。

  • gtkmm

    gtkmm 是流行的图形界面库 GTK+ 的官方 C++ 接口。

  • 其他

    • imgui
    • duilib
    • xcgui
    • GuiLite
    • soui

QT Hello World

QT 运行机制:

  • 项目组织文件 .pro 存储项目设置

  • 主程序入口文件 main.cpp,用于实现 main 函数

  • 界面文件 widget.ui ,使用 XML 格式描述元件及布局,xxx.ui 文件经过 uic 转换工具,转换生成 ui_xxx.h,成为 main 函数的头文件

  • widget.h 是设计的窗体类的头文件,widget.cpp 是实现文件,任何窗体或界面组件都是用类封装的。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CWIk2yTM-1660304483403)(image-20220812131106772.png)]

#include "widget.h"
#include <QLabel>
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QLabel *hello = new QLabel("Hello world!");
    hello->show();
    return a.exec();
}

运行结果如下

在这里插入图片描述

(丑是丑点,但是两行代码还要什么自行车啊…)

8.11

Qt 基础窗口、对话框

在这里插入图片描述

Qt 常用组件

可视化 UI 设计——布局管理
  1. Qt 提供的常用布局:

    • QHBoxLayout:按水平方向从左到右布局
    • QVBoxLayout:按竖直方向从上到下布局
    • QGridLayout:在一个网格中进行布局,类似于 HTML 的 table
  2. 利用 widget 做布局:

    利用控件里的 Containers-widget 做布局,在 widget 中的控件可以进行水平、垂直、栅格布局等操作,灵活性很强。

常用组件
  1. 按钮类——Buttons

    Buttons功能
    Push Button按钮
    Tool Button工具按钮
    Radio Button单选按钮
    Check Button复选框
    Command Link Button命令链接按钮
    Dialog Button Box对话框按钮盒
  2. 输入部件类——Input Widgets

    Input Widgets功能
    Combo Box组合框
    Font Combo Box字体组合框
    Line Edit行编辑框
    Text Edit文本编辑框
    Plain Text Edit纯文本编辑框
    Spin Box数字显示框
    Double Spin Box数字显示框
    Time Edit时间编辑
    Data Edit日期编辑
    Data/Time Edit日期/时间编辑
  3. 现实控件类——Display Widgets

    Display Widgets功能
    Label标签
    Text Browser文本浏览器
    Graphics View图形视图
    Calendar Widget日历
    LCD Number液晶数字
    Progress Bar进度条
  4. 空间间隔类——Spacers

    Spacers功能
    Horizontal Spacer水平间隔
    Vertical Spacer垂直间隔
  5. 布局管理类——Layouts

    Layouts功能
    Vertical Layout垂直布局
    Horizontal Layout水平布局
    Grid Layout网格布局
    Form Layout表单布局
  6. 容器类——Containers

    Containers功能
    Group Box组框
    Scroll Area滚动区域
    Tool Box工具箱
    Tab Widget标签部件
    Stacked Widget堆叠部件
    Frame框架
    Widget小部件
    Dock Widget停靠窗体部件
  7. 项目识图类——Item Views

    Item Views功能
    List view列表视图
    Tree View树形视图
    Table View表格式视图
    Column View列视图
    Undo View撤销视图
  8. 项目控件类——Item Widgets

    Item Widgets功能
    List Widget列表控件
    Tree Widget树形控件
    Table Widget表格控件

软件工程

基本流程
  1. 需求分析阶段

    对解决的问题进行详细的分析,得出问题的需求,包括需要输入什么数据,要得到什么结果,最后输出什么,软件需求包括功能需求、非功能需求、设计约束。

  2. 设计阶段

    从工程管理角度看,软件设计可分为系统设计、概要设计和详细设计。

    • 系统设计是把需求转化为软件系统最重要的环节,系统设计的优劣在根本上决定了软件系统的质量。系统设计主要包括软件体系结构设计,确定系统由那些模块组成以及各个模块之间的关系和资源分配。
    • 概要设计以模块为单位,主要是构建模块的基本层次结构、数据结构、算法设计、模块的整体流程设计、模块间的接口设计等。概要设计用于指导详细设计,为详细设计提供依据。
    • 详细设计是对概要设计的细化,对于概要设计中本模块内部定性设计的内容进一步量化。指导编码是编码的一局,详细设计的粒度应当达到让编码者看到设计书就知道代码如何编写的程度。

    广义上设计阶段还包含开发环境选定和开发平台选定。

  3. 编码和调试阶段

    编码和调试阶段需要完成的工作包括代码编制、编译和链接、调试等。

  4. 软件测试阶段

    测试是软件开发过程中的一个综合过程,一般软件开发过程中的测试工作要占整个开发工作量的一半以上。

    原理上软件开发测试所采用的方法为:白盒测试、黑盒测试、路径测试、覆盖测试等不同方法。

可分为系统设计、概要设计和详细设计。

  • 系统设计是把需求转化为软件系统最重要的环节,系统设计的优劣在根本上决定了软件系统的质量。系统设计主要包括软件体系结构设计,确定系统由那些模块组成以及各个模块之间的关系和资源分配。
  • 概要设计以模块为单位,主要是构建模块的基本层次结构、数据结构、算法设计、模块的整体流程设计、模块间的接口设计等。概要设计用于指导详细设计,为详细设计提供依据。
  • 详细设计是对概要设计的细化,对于概要设计中本模块内部定性设计的内容进一步量化。指导编码是编码的一局,详细设计的粒度应当达到让编码者看到设计书就知道代码如何编写的程度。

广义上设计阶段还包含开发环境选定和开发平台选定。

  1. 编码和调试阶段

    编码和调试阶段需要完成的工作包括代码编制、编译和链接、调试等。

  2. 软件测试阶段

    测试是软件开发过程中的一个综合过程,一般软件开发过程中的测试工作要占整个开发工作量的一半以上。

    原理上软件开发测试所采用的方法为:白盒测试、黑盒测试、路径测试、覆盖测试等不同方法。

8.12

QT 信号(signal)和槽(slot)机制

什么是信号和槽

信号和槽,就是用于 QT 中对象间的通信的机制。

信号和槽机制,是 QT 元对象模型的一部分功能,必须有元对象的支持。

在定义类中加上 Q_OBJECT ,就使类具备了元对象的功能,一般默认添加

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
};
信号和槽的实现
1.直接利用信号槽编辑器

在设计板块点击此按钮后,长按一个控件

在这里插入图片描述

指向哪,就和哪个控件相连
在这里插入图片描述

之后弹出一个选择对连接的操作选择界面
在这里插入图片描述

如果勾选“显示从 QWidgets 继承的信号和槽”复选框,将显示更多类型的槽

在这里插入图片描述

这样的信号和槽实现方式非常简单,但是局限性也很大,功能有限

2.右键转到槽

控件编辑器中,直接右键点击控件,选择“转到槽”,弹出如下界面
在这里插入图片描述

槽定义自动生成,clinked 由系统生成和处理,系统自动添加调用点和访问点

在这里插入图片描述

写入了如下内容

void Widget::on_pushButton_clicked()
{
    qDebug()<<"我只是一个弱小的按钮罢了";
}

点击所选择的按钮后,就发生了对应的操作
在这里插入图片描述

这样的实现方式比较简单,功能也比较丰富,是经常使用的方式,但是对于没有界面控件的对象(代码生成的对象)没有办法使用

3.自定义信号和槽

自定义信号槽可以连接 QT 中所有包含 Q_OBJECT 的对象,用 QObject::connect() 连接

connect(参数1,参数2,参数3,参数4);(一个 connect 只能连一个槽)

  • 参数1:发送信号的对象地址
  • 参数2:发送的信号
  • 参数3:接受信号的对象地址
  • 参数4:接收信号后的槽函数

在 widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QObject::connect(this,SIGNAL(mySignal()),this,SLOT(mySlot()));
}

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


void Widget::on_pushButton_clicked()
{
    qDebug() <<"第一个按钮触发,发送信号";
    emit mySignal();
}

void Widget::mySlot()
{
    qDebug()<<"第二个按钮触发";
}

在 widget.h

#ifndef WIDGET_H
#define WIDGET_H
#include <QDebug>
#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void mySlot();
    void on_pushButton_clicked();

signals:
    void mySignal();//信号就是个函数声明,没有函数体
private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

运行结果

在这里插入图片描述

这个方式实现信号和槽,功能强大,可以连接任意对象,难度较高

8.15

QT 文件操作

QFile 文件操作

QFile 是 QT 框架提供的来专门操作文件的类。

QFile 类支持对文件进行读取、写入、删除、重命名、拷贝等操作,它既可以操作文本文件,也可以操作二进制文件。

QFile 类构造函数

使用 QFile 类操作文件之前,程序中需要引入 头文件,创建 QFile 类的对象,常用的构造函数有:QFile::Qfile() 和 QFile::QFile(const QString &name)

name 用于操作目标文件,包含文件的存储路径和文件名,存储路径可以使用绝对路径和相对路径

通常情况下,调用第二个构造函数,直接指明要操作的文件,对于第一个构造函数所创建的对象,需要调用 setFileName() 方法指明要操作的文件

在用 QFile 读写文件之前必须先打开文件,调用 open() 成员方法

bool QFile::open(OpenMode mode);
相对路径 绝对路径
  • 相对路径:从当前目录开始定位,形成的一个路径。
  • 绝对路径:从根目录(例如盘符,C盘D盘)开始定位,形成的一个路径。

在这里插入图片描述

例如在文件夹1目录下,想去访问文件夹2目录下的文件

​ (从 文件夹\文件夹1 访问 文件夹2下的 test )

  • 相对路径写法:…\文件夹2\test …\作用类似于返回
  • 绝对路径写法:d:\文件夹\文件夹2\test
QFile 文件打开方式
  • QIODevice::ReadOnly——只读操作
  • QIODevice::WriteOnly——只写,如果不存在目标文件则创建一个
  • QIODevice::ReadWrite——对文件进行读写操作
  • QIODevice::Append——追加写入,数据会追加到文件的末尾
  • QIODevice::Truncate——以重写模式打开,写入数据会把原有数据覆盖,此代开方式不能单独使用,通常会和 ReadOnly 和 WriteOnly 搭配
  • QIODevice::Text——读取文件时会把行尾结束符转换成本格式

QIODevice 是 QT 中所有 I/O 设备的基础接口类,为注入 QFile、QBuffer 等支持读写数据块的设备提供一个抽象接口。

如果需要,可以为 mode 参数一次性提供多个值,用 | 分割

QIODevice 方法列表
方法功能
qint64 QFile::size() const获取当前文件的大小。对于打开的文件,该方法返回文件中可以读取的字节数。
bool QIODevice::getChar(char *c)从文件中读取一个字符,并存储到 c 中。读取成功时,方法返回 true,否则返回 false。
bool QIODevice::putChar(char c)向文件中写入字符 c,成功时返回 true,否则返回 false。
QByteArray QIODevice::read(qint64 maxSize)从文件中一次性最多读取 maxSize 个字节,然后返回读取到的字节。
qint64 QIODevice::read(char *data, qint64 maxSize)从文件中一次性对多读取 maxSize 个字节,读取到的字节存储到 data 指针指定的内存控件中。该方法返回成功读取到的字节数。
QByteArray QIODevice::readAll()读取文件中所有的数据。
qint64 QIODevice::readLine(char *data, qint64 maxSize)每次从文件中读取一行数据或者读取最多 maxSize-1 个字节,存储到 data 中。该方法返回实际读取到的字节数。
qint64 QIODevice::write(const char *data, qint64 maxSize)向 data 数据一次性最多写入 maxSize 个字节,该方法返回实际写入的字节数。
qint64 QIODevice::write(const char *data)将 data 数据写入文件,该方法返回实际写入的字节数。
qint64 QIODevice::write(const QByteArray &byteArray)将 byteArray 数组中存储的字节写入文件,返回实际写入的字节数。
bool QFile::copy(const QString &newName)将当前文件的内容拷贝到名为 newName 的文件中,如果成功,方法返回 true,否则返回 false。 copy 方法在执行复制操作之前,会关闭源文件。
bool QFile::rename(const QString &newName)对当前文件进行重命名,新名称为 newName,成功返回 true,失败返回 false。
bool QFile::remove()删除当前文件,成功返回 true,失败返回 false。

8.16

QT 网络编程

TCP/IP

TCP/IP 是一个协议簇,包括很多协议,其中 TCP、IP 协议是两个很重要的协议。TCP/IP 协议集包括应用层、传输层、网络层、网络访问层

  • TCP (Transmission Control Protocol,传输控制协议)是面向连接的协议,是流模式,在收发数据前,必须和对方建立可靠的连接,经过三次数据交换才能建立起 TCP 连接,也称为三次握手:

    第一次握手:主机A通过向主机B 发送一个含有同步序列号的标志位的数据段给主机B,向主机B 请求建立连接,通过这个数据段, 主机A告诉主机B 两件事:我想要和你通信;你可以用哪个序列号作为起始数据段来回应我。

    第二次握手:主机B 收到主机A的请求后,用一个带有确认应答(ACK)和同步序列号(SYN)标志位的数据段响应主机A,也告诉主机A两件事:我已经收到你的请求了,你可以传输数据了;你要用那个序列号作为起始数据段来回应我

    第三次握手:主机A收到这个数据段后,再发送一个确认应答,确认已收到主机B 的数据段:"我已收到回复,我现在要开始传输实际数据了,这样3次握手就完成了,主机A和主机B 就可以传输数据了

    断开连接需要四次:

    第一次: 当主机A完成数据传输后,将控制位FIN置1,提出停止TCP连接的请求 ;

    第二次: 主机B收到FIN后对其作出响应,确认这一方向上的TCP连接将关闭,将ACK置1;

    第三次: 由B 端再提出反方向的关闭请求,将FIN置1 ;

    第四次: 主机A对主机B的请求进行确认,将ACK置1,双方向的关闭结束.。

  • UDP(User Data Protocol,用户数据报协议)是非连接的协议,传输数据之前源端和终端不建立连接,也不需要维护连接状态,可以用一台服务器向多个客户机传输相同的消息。吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。UDP 是面向报文的,发送方的UDP对应用程序交下来的报文, 在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界, 因此,应用程序需要选择合适的报文大小。我们所用的 ping 就是发送 UDP 数据包,检测网络通断状况。

网络通信流程

使用 UDP 进行通信,服务器和客户端的处理步骤比 TCP 简单得多,并且两端是对等的,没有严格意义上的客户端和服务器端

在这里插入图片描述

使用 TCP 进行通信,建立的是双向连接,安全性高,流式传输下发送端和接收端的数据量可以不一致

在这里插入图片描述

QT 实现网络通信

QT 提供的类基于 TCP 的套接字通信用到两个类:

  • QTcpServer 服务器类,用于监听客户端连接以及和客户端建立连接
  • QTcpSocket 通信的套接字类,客户端、服务器端都需要使用

在 QT 中所有用于网络的模块都包含在 network 中
在这里插入图片描述

8.17

QT 登录界面制作

制作一个未连接数据库的登录界面

先上成果图

在这里插入图片描述

先新建一个 Qt 设计师界面类 文件

然后用如下控件做成登录所用的 UI 界面

在这里插入图片描述

实现代码

loginscreen.h

#ifndef LOGINSCREEN_H
#define LOGINSCREEN_H

#include <QWidget>
#include <QMessageBox>
#include <QJsonDocument>
#include <QFile>
#include <QDebug>
#include <QJsonObject>
#include <QByteArray>

namespace Ui {
class LoginScreen;
}

class LoginScreen : public QWidget
{
    Q_OBJECT

public:
    explicit LoginScreen(QWidget *parent = nullptr);
    ~LoginScreen();


signals:
    void login();//登录
    void close_LoginScreen();//关闭登录界面信号

public slots:
    void button_login_clicked();//按下登录按钮

private slots:
    void on_button_login_clicked();

private:
    Ui::LoginScreen *ui;

    QString myida;
    QString mykeya;
    QString myidb;
    QString mykeyb;
};

#endif // LOGINSCREEN_H

loginscreen.cpp

#include "loginscreen.h"
#include "ui_loginscreen.h"
#include <QDebug>
LoginScreen::LoginScreen(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::LoginScreen)
{
    ui->setupUi(this);
    //利用信号槽 触发登录按钮后
    //connect(this,SIGNAL(on_button_login_clicked()),this,SLOT(botton_login_clicked()));
    //connect(this,SIGNAL(close_LoginScreen()),this,SLOT(close()));

    //在输入密码时显示点,防止窥视
    qDebug()<<"13";
    ui->edit_key->setEchoMode(QLineEdit::Password);

    myida="ypf20212241344";
    mykeya="20212241344";
    myidb="fpy20212241344";
    mykeyb="20212241344";
}

void LoginScreen::button_login_clicked()
{
    //从输入框中获取账号和密码
    QString id = ui->edit_id->text();
    QString key = ui->edit_key->text();

    if((id == myida && key == mykeya)||(id == myidb && key == mykeyb))
    {
        emit(login());
        emit(close_LoginScreen());
        this->close();
    }
    else
        QMessageBox::information(this,"warning","账号或密码输入错误!");
}


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


void LoginScreen::on_button_login_clicked()
{
    button_login_clicked();
}

mainwindows.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "loginscreen.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    LoginScreen *mylogin;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    mylogin = new LoginScreen;
    mylogin->show();
    connect(mylogin,SIGNAL(login()),this,SLOT(show()));
}

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


main.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    mylogin = new LoginScreen;
    mylogin->show();
    connect(mylogin,SIGNAL(login()),this,SLOT(show()));
}

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


注意需要把 logincreen 这几个文件导入到主程序的 QT 中,单导入文件夹是可以访问到的,但是 QT 不会报错和 debug,需要手动单机文件夹导入

在这里插入图片描述

8.18

阿里云 MYSQL 创建

根据小学期的项目需求来看,需要用到数据库,货比三家后在大佬推荐下最后选择了阿里云的 RDS 数据库,主要是便宜物美价廉。
在这里插入图片描述

然后利用 Navicat 16 连接上了数据库,需要先申请公网 IP,并设置白名单后才可以访问

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值