【QT】TCP/UDP详解及实现

news2024/11/13 9:17:35

TCP/UDP

    • TCP/IP模型
    • TCP协议
        • 头部格式
        • 三次握手
        • 四次挥手
    • UDP协议
        • 头部格式
    • Socket编程
        • tcp
        • udp
        • 代码实现
            • 服务端:
            • 客户端:
    • 总结

TCP/IP模型

TCP模型是一个常见的网络协议参考模型,也称为TCP/IP模型或互联网模型。它是指TCP/IP协议族中的一组协议,用于在计算机网络中进行数据通信。TCP模型由四个层次组成,分别是:

  1. 应用层(Application Layer):

    应用层是最靠近用户的层次,为用户提供各种网络应用服务。
    包括常见的应用层协议,如HTTP、FTP、SMTP、DNS等。
    该层定义了应用程序之间的通信规则和数据格式。

  2. 传输层(Transport Layer):

    传输层负责提供可靠的端到端通信和数据传输服务。
    最常用的传输层协议是TCP和UDP。
    TCP提供可靠的、面向连接的通信服务,保证数据的可靠性、有序性和流量控制。
    UDP是一种无连接的传输协议,提供简单的、不可靠的数据传输服务。

  3. 网络层(Network Layer):

    网络层负责将数据从源主机传输到目标主机,处理主机之间的路径选择和数据包转发。
    最常用的网络层协议是IP(Internet Protocol)。
    IP协议定义了数据在网络中的寻址和路由机制,将数据分割成数据包进行传输。

  4. 链路层(Link Layer):

    链路层是最底层的层次,负责实际的物理链路传输和网络适配。
    包括以太网、Wi-Fi、PPP等不同的链路层协议。
    链路层将数据包封装成帧,并通过物理介质进行传输。
    TCP模型是一个分层结构,每个层次具有特定的功能和责任,通过不同层次的协议进行通信。它提供了一个标准化的网络通信框架,使不同的计算机和网络设备可以互相通信和交换数据。TCP/IP模型被广泛应用于互联网和许多局域网中,成为现代计算机网络的基础。

TCP协议

头部格式

在这里插入图片描述

  1. 序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。
  2. 确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。
  3. ACK:该位为 1 时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1 。
  4. RST:该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接。
  5. SYN:该位为 1 时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。
  6. FIN:该位为 1 时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换 FIN 位为 1 的 TCP 段。

三次握手

  1. 第一次握手(SYN):

    客户端向服务器发送一个SYN(同步)包,表示客户端请求建立连接,并指定初始序列号。
    客户端将SYN包的Sequence Number设置为一个随机数,用于后续数据传输的序号标识。

验证了客户端的发送能力和服务端的接收能力

  1. 第二次握手(SYN-ACK):

    服务器收到客户端的SYN包后,向客户端发送一个SYN-ACK(同步-确认)包作为响应。
    服务器将自己的Sequence Number设置为一个随机数,用于后续数据传输的序号标识。
    服务器同时将ACK标志和确认序号设置为客户端的初始序列号加1,并将自己的初始序列号放入ACK包中,表示服务器接受客户端的连接请求。

验证了服务端的发送能力和客户端的接收能力

  1. 第三次握手(ACK):

    客户端收到服务器的SYN-ACK包后,向服务器发送一个ACK(确认)包,确认连接请求。
    客户端将自己的Sequence Number设置为服务器的初始序列号加1,并将ACK标志和确认序号设置为服务器的初始序列号加1,表示客户端确认服务器的连接响应。

验证了客户端及服务端的发送及接收能力
在这里插入图片描述

小节:通过这三次握手,客户端和服务器都能确认彼此的通信能力,并建立起可靠的双向连接。每次握手过程都包含了序列号和确认序列号的交换,用于确保数据的可靠传输。同时,三次握手也能防止旧的连接请求在网络中滞留导致的错误连接建立。

四次挥手

TCP的四次挥手是在关闭TCP连接时使用的挥手过程,用于确保双方完成数据的传输并安全关闭连接。下面是TCP四次挥手的详细过程:

  1. 第一次挥手(FIN):

    客户端向服务器发送一个FIN(结束)包,表示客户端没有更多的数据要发送。
    客户端进入FIN_WAIT_1状态,等待服务器的确认。

  2. 第二次挥手(ACK):

    服务器收到客户端的FIN包后,向客户端发送一个ACK(确认)包作为响应。
    服务器进入CLOSE_WAIT状态,表示已经关闭了客户端到服务器的数据传输。

  3. 第三次挥手(FIN):

    等到服务端处理完数据后,服务器向客户端发送一个FIN包,表示服务器也没有更多的数据要发送。
    服务器进入LAST_ACK状态,等待客户端的确认。

  4. 第四次挥手(ACK):

    客户端收到服务器的FIN包后,向服务器发送一个ACK包作为确认。
    客户端进入TIME_WAIT状态,等待一段时间,以确保服务器收到了确认,并允许时间足够长来处理可能到达的延迟的数据。
    服务器收到客户端的确认后,关闭连接,进入CLOSED状态。
    客户端等待一段时间后,关闭连接,也进入CLOSED状态。
    在这里插入图片描述
    小节:通过这四次挥手,双方确认彼此不再发送数据,并完成了连接的关闭过程。这样可以确保双方都有足够的时间来处理未处理的数据,并避免数据丢失或中断。四次挥手过程中,每次挥手都包含了序列号和确认序列号的交换,用于确保数据的可靠传输和连接的正确关闭。

UDP协议

与TCP协议相比,UDP数据传输是建立在非链接的基础之上的。udp 传输数据就是将数据简单的封装一下然后在通过网卡发送出去即可,数据包之间并没有状态上的链接。

头部格式

在这里插入图片描述

  1. 目标和源端口:主要是告诉 UDP 协议应该把报文发给哪个进程。
  2. 包长度:该字段保存了 UDP 首部的长度跟数据的长度之和。
  3. 校验和:校验和是为了提供可靠的 UDP 首部和数据而设计,防止收到在网络传输中受损的 UDP 包。

Socket编程

tcp

  1. 创建套接字(Socket):

    在客户端和服务器端都需要创建一个套接字对象,用于建立TCP连接。
    在C/C++中,可以使用socket()函数创建套接字对象,并指定协议族(如AF_INET)和套接字类型(如SOCK_STREAM)。

  2. 绑定地址和端口(服务器端):

    在服务器端,需要将套接字绑定到一个特定的IP地址和端口上,以便监听客户端的连接请求。
    可以使用bind()函数将套接字与地址和端口绑定。

  3. 监听连接请求(服务器端):

    在服务器端,需要开始监听来自客户端的连接请求。
    可以使用listen()函数将套接字设置为监听状态,指定最大连接数(backlog)。

  4. 发起连接(客户端):

    在客户端,需要与服务器建立连接。
    可以使用connect()函数将套接字连接到服务器的地址和端口。

  5. 接受连接(服务器端):

    当服务器端收到客户端的连接请求时,需要接受连接。
    可以使用accept()函数接受客户端的连接请求,并返回一个新的套接字对象用于与该客户端通信。

  6. 数据传输:

    一旦连接建立,客户端和服务器端可以通过套接字进行数据传输。
    在客户端,可以使用send()函数发送数据到服务器端。
    在服务器端,可以使用recv()函数接收客户端发送的数据。

  7. 关闭连接:

    当数据传输完成或连接不再需要时,需要关闭连接。
    在客户端和服务器端,可以使用close()或closesocket()函数关闭套接字。

udp

  1. 创建套接字(Socket):

    在客户端和服务器端都需要创建一个UDP套接字对象,用于进行UDP通信。
    在C/C++中,可以使用socket()函数创建套接字对象,并指定协议族(如AF_INET)和套接字类型(如SOCK_DGRAM)。

  2. 绑定地址和端口(服务器端):

    在服务器端,需要将套接字绑定到一个特定的IP地址和端口上,以便监听客户端的连接请求。
    可以使用bind()函数将套接字与地址和端口绑定。

  3. 发送数据(客户端):

    在客户端,可以使用sendto()函数向服务器发送数据包。
    需要指定服务器的IP地址和端口,以及要发送的数据。

  4. 接收数据(服务器端):

    在服务器端,可以使用recvfrom()函数接收客户端发送的数据包。
    可以通过该函数获取客户端的IP地址和端口,以及接收到的数据。

  5. 处理数据:

    在接收到数据后,可以对其进行处理和解析。
    根据应用需求,可以对数据进行解析、验证、处理等操作。

  6. 发送响应(服务器端):

    在服务器端,可以使用sendto()函数向客户端发送响应数据包。
    需要指定客户端的IP地址和端口,以及要发送的响应数据。

  7. 关闭套接字:

    当UDP通信完成或不再需要时,需要关闭套接字。
    可以使用close()或closesocket()函数关闭套接字。

代码实现

实验由一个客户端程序和一个服务器端程序组成,用QT实现连接通信。运行界面如下所示:
在这里插入图片描述

服务端:

server.h:

#ifndef SERVER_H
#define SERVER_H

#include <QMainWindow>
#include<QTcpServer>
#include<QTcpSocket>
#include<QUdpSocket>

QT_BEGIN_NAMESPACE
namespace Ui { class server; }
QT_END_NAMESPACE

class server : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void on_pushButton_listen_clicked();

    void server_new_connect();

    void socket_read_data();

    void read_data();



private:
    Ui::server *ui;
    QUdpSocket *uServer;
    QTcpServer *mServer;
    QTcpSocket *mSocket;
    int i1,i2;
    int j1,j2;
};
#endif // SERVER_H

server.cpp

#include "server.h"
#include "ui_server.h"
#include<qdebug.h>

server::server(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::server)
{
    ui->setupUi(this);
    ui->portEdit->setText("8080");

    mServer=new QTcpServer;

    connect(mServer,&QTcpServer::newConnection,this,&server::server::server_new_connect);

    uServer=new QUdpSocket;
    uServer->bind(QHostAddress("192.168.1.107"),8080);
    QObject::connect(uServer,&QUdpSocket::readyRead,this,&server::read_data);
}

void server::read_data()
{
    qDebug()<<"recv_UDP";
    if(ui->radioButton_UDP->isChecked())
    {
        qDebug()<<"recv_UDP";

        QByteArray arr;//创建QByteArray对象存储缓冲区数据
        arr.resize(uServer->bytesAvailable());//设置字符串大小
        uServer->readDatagram(arr.data(),arr.size());//读取缓冲区数据
        qDebug()<<uServer->readDatagram(arr.data(),arr.size());

        QString str ;//创建QString对象用于进行缓冲数据的处理
        str.prepend(arr);//QByteArray转QString
        qDebug()<<"str="<<str;
        ui->textEdit->setText("udp:"+str);
    }
}

server::~server()
{
    uServer->close();
    uServer->deleteLater();
    mServer->close();
    mServer->deleteLater();
    delete ui;
}

void server::on_pushButton_listen_clicked()
{
    if(ui->pushButton_listen->text() == QString::fromLocal8Bit("侦听"))
    {
        int port = ui->portEdit->text().toInt();
        if(!mServer->listen(QHostAddress("192.168.1.107"),port))//判断侦听本机端口和地址是否成功
        {
            ui->portEdit_state->setText(QString::fromLocal8Bit("侦听失败!"));//侦听失败
            qDebug()<<mServer->errorString();
            return;
        }
        ui->pushButton_listen->setText(QString::fromLocal8Bit("取消侦听"));//改变按键功能
        ui->portEdit_state->setText(QString::fromLocal8Bit("侦听成功!"));//侦听成功
        qDebug()<<"Listen successful!";
    }
    else//侦听失败
    {
        mSocket->abort();//销毁TCP套接字对象
        mServer->close();
        ui->portEdit_state->setText(QString::fromLocal8Bit("侦听失败!"));//返回侦听失败
        ui->pushButton_listen->setText(QString::fromLocal8Bit("侦听"));//改变按键功能

    }
}

void server::server_new_connect()
{
    mSocket = mServer->nextPendingConnection();
    QObject::connect(mSocket,&QTcpSocket::readyRead,this,&server::socket_read_data);//连接函数槽
    ui->portEdit_state->setText(QString::fromLocal8Bit("连接成功!"));
    qDebug()<<"A client connect!";
}

void server::socket_read_data()
{
    if(ui->radioButton_TCP->isChecked())
    {
        QString str= mSocket->readAll();
        qDebug()<<str;
        qDebug()<<"recv_TCP";
        ui->textEdit->setText("tcp:"+str);

    }

}
客户端:

client.h

#ifndef CLIENT_H
#define CLIENT_H

#include <QMainWindow>
#include<QTcpServer>
#include<QTcpSocket>
#include<QHostAddress>
#include<QFile>
#include<QTimer>
#include<QMessageBox>
#include<QUdpSocket>

QT_BEGIN_NAMESPACE
namespace Ui { class client; }
QT_END_NAMESPACE

class client : public QMainWindow
{
    Q_OBJECT

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


private slots:
    void socket_disconnected();
    void on_pushButtonconnect_clicked();
    void on_pushButton_send_clicked();


private:
    Ui::client *ui;
    QTcpSocket *mSocket;
    QUdpSocket *uSocket;
    QTimer *tim;
};
#endif // CLIENT_H

client.cpp

#include "client.h"
#include "ui_client.h"
#include<qdebug.h>

client::client(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::client)
{
    ui->setupUi(this);
    ui->ipEdit->setText("192.168.1.107");//默认显示ip为192.168.1.44
    ui->portEdit->setText("8080");//默认显示端口为8080
    mSocket = new QTcpSocket();//TCP套接字初始化
    ui->pushButton_send->setEnabled(true);
    //QObject::connect(mSocket,&QTcpSocket::readyRead,this,&client::on_pushButton_send_clicked);
    QObject::connect(mSocket,&QTcpSocket::disconnected,this,&client::socket_disconnected);
    uSocket = new QUdpSocket(this);//UDP套接字初始化

    tim = new QTimer();//初始化计时器对象
    tim->setInterval(1000);//设置计时器间隔时间为1s

    connect(tim,SIGNAL(timeout()),this,SLOT(onTimeOut()));//连接信号槽
    tim->start();//初始化计时器状态


}

client::~client()
{
    delete this->uSocket;
    delete this->mSocket;
    delete ui;
}

/*TCP连接*/
void client::on_pushButtonconnect_clicked()
{
    if(ui->pushButtonconnect->text() == QString::fromLocal8Bit("连接"))
        {
            QString IP;
            int port;
            IP = ui->ipEdit->text(); //获取IP地址
            port = ui->portEdit->text().toInt(); //获取端口号
            mSocket->abort();//取消已有的连接
            mSocket->connectToHost(IP, port);//连接服务器
            if(!mSocket->waitForConnected(3000))//等待连接成功
            {
                qDebug() << "Connection failed!";
                ui->lineEdit_state->setText(QString::fromLocal8Bit("连接失败!"));
                return;
            }
            qDebug() << "Connect successfully!";
            ui->lineEdit_state->setText(QString::fromLocal8Bit("连接成功!"));
            ui->pushButton_send->setEnabled(true);//发送按键使能
            ui->pushButtonconnect->setText(QString::fromLocal8Bit("断开连接"));//修改按键文字
        }
        else
        {
            mSocket->disconnectFromHost();//断开连接
            ui->pushButtonconnect->setText(QString::fromLocal8Bit("连接"));//修改按键文字
            ui->pushButton_send->setEnabled(true);//发送按键使能
        }
}

/*发送数据*/
void client::on_pushButton_send_clicked()
{
    qDebug()<<"Send: "<<ui->textEdit_enter->toPlainText().toLatin1();

    if(ui->radioButton_TCP->isChecked())//判断使用TCP协议
    {
        qDebug()<<"TCP";
        mSocket->write(ui->textEdit_enter->toPlainText().toLatin1());//tcp协议下客户端发送框内容写入缓冲
        mSocket->flush();
    }
    else if(ui->radioButton_UDP->isChecked())//判断使用UDP协议
    {
        qDebug()<<"UDP";
        uSocket->writeDatagram(ui->textEdit_enter->toPlainText().toLatin1(),QHostAddress("192.168.1.107"),8080);//udp协议下客户端发送框内容写入缓冲
        uSocket->flush();
    }
    else
    {
        ui->lineEdit_state->setText("choose TCP or UDP ");//未选择协议
    }
}

/*断开连接*/
void client::socket_disconnected()
{
    ui->pushButton_send->setEnabled(false);//关闭发送按键
    ui->pushButtonconnect->setText(QString::fromLocal8Bit("连接"));//显示
    qDebug()<<"Disconnected!";
}

总结

TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)是两种常用的传输层协议,用于在计算机网络中传输数据。它们具有不同的特点和适用场景,以下是对TCP和UDP的总结:
TCP

  • TCP是一种面向连接的协议,提供可靠的数据传输和错误检测机制。
  • TCP使用三次握手建立连接,确保数据的可靠性和有序性。
  • TCP提供流式传输,将数据分割成TCP报文段,并通过序号和确认应答来保证数据的正确性和完整性。
  • TCP具有拥塞控制机制,可以根据网络状况动态调整传输速率,以避免网络拥塞。
  • TCP适用于需要可靠传输的应用,如文件传输、电子邮件、Web浏览等。

UDP

  • UDP是一种无连接的协议,提供低延迟和高效率的数据传输。
  • UDP不建立连接,直接将数据报文发送出去,不保证数据的可靠性和有序性。
  • UDP是一种无状态的协议,不维护连接状态信息,每个数据报文都是独立的。
  • UDP适用于实时性要求较高的应用,如实时音视频传输、在线游戏等。
  • UDP较TCP具有较小的开销,传输速度快,但不提供拥塞控制和重传机制。
  • 由于UDP不保证数据的可靠性,应用程序需要自行处理数据的丢失、重复和顺序问题。

选择使用TCP还是UDP取决于应用的需求和特点。如果应用程序需要可靠传输、有序性和拥塞控制,应选择TCP。而如果应用程序对实时性要求较高,可以容忍一些数据丢失或顺序混乱,且需要较低的延迟,那么选择UDP更合适。

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

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

相关文章

总结:Linux系统上面定时备份mysql指定数据库的解决方案

总结&#xff1a;Linux系统上面定时备份mysql指定数据库的解决方案 一Mysql数据库本身就自带备份数据库命令1.mysql本身自带备份数据库为一个sql文件的命令&#xff0c;只需要在操作系统的终端里面执行就好了 二Linux和Unix操作系统都自带一个定时任务执行器&#xff1a;cronta…

浅结反静态调试2

文章目录 SMC 自解码什么是SMC&#xff1f;原理示例动调 SMC 自解码 什么是SMC&#xff1f; 简而言之&#xff0c;就是程序中的部分代码在运行之前被加密成一段数据&#xff0c;不可反编译&#xff0c;通过程序运行后执行相关的解码功能&#xff0c;对加密的代码数据进行动态…

Linux :: vim 编辑器的初次体验:三种 vim 常用模式 及 使用:打开编辑、退出保存关闭vim

前言&#xff1a;本篇是 Linux 基本操作篇章的内容&#xff01; 笔者使用的环境是基于腾讯云服务器&#xff1a;CentOS 7.6 64bit。 学习集&#xff1a; C 入门到入土&#xff01;&#xff01;&#xff01;学习合集Linux 从命令到网络再到内核&#xff01;学习合集 目录索引&am…

配置Linux操作系统主机名及网络设置

上一篇我们讲到了如何克隆虚拟机&#xff0c;三台虚拟机Spark01、Spark02和Spark03默认为动态IP地址&#xff0c;若后续重启系统后IP地址便会发生改变&#xff0c;非常不利于实际开发&#xff0c;且虚拟机Spark02和Spark03是通过克隆虚拟机Spark01创建的&#xff0c;这会导致这…

软件测试银行项目到底“香”到哪里?

为什么做金融类软件测试&#xff1f; 做金融类软件测试的原因有以下几个&#xff1a; 保障客户资产安全&#xff1a;金融类软件通常涉及大量的客户财产和敏感信息&#xff0c;因此软件测试可以帮助发现潜在的漏洞和风险&#xff0c;从而确保客户的资产和信息得到充分的保护。 …

超详细IDEA:MavenWeb项目配置Tomcat

文章目录 附IDEA创建MavenWeb项目教程附Windows 10安装配置Tomcat教程一、插件配置Tomcat方式二、IDEA部署本地Tomcat方式 附IDEA创建MavenWeb项目教程 超详细IDEA创建MavenWeb项目教程 附Windows 10安装配置Tomcat教程 超详细Windows 10安装配置Tomcat教程 一、插件配置To…

LeetCode: 238. 除自身以外数组的乘积

目录 1. 解法一&#xff1a;时&#xff1a;O(N) &#xff0c;空&#xff1a;O(N) 2. 解法二&#xff1a;(解法一的空间优化) 时&#xff1a;O(N)&#xff0c;空&#xff1a;O(1) 3. 解法三 原题链接&#xff1a;238. 除自身以外数组的乘积 - 力扣&#xff08;Leetcode&#x…

java SSM 教务管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM 教务管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/…

网工内推 | 云方向招运维,云计算HCIE认证优先,最高22k

01 东华软件股份公司 招聘岗位&#xff1a;运维系统工程师&#xff08;云平台&#xff09; 职责描述&#xff1a; 1、 负责华为云平台Huawei CloudStack &#xff0c;FusionStorage分布式存储的维护&#xff0c;优化和故障处理&#xff1b; 2、 负责云平台上VDC、ECS、DDM、R…

1 Linux网络虚拟化

Linux网络虚拟化 文章目录 Linux网络虚拟化前言一、network namespace1.1 初识network namespace1.2 配置network namespace 二、veth pair三、容器与host veth pair的关系3.1 方法一3.2 方法二3.2 方法三 四、 Linux bridge4.1 Linux bridge初体验4.2 把IP让给Linux bridge4.3…

RestCloud-新一代(智能)全域数据集成平台

新一代智能全域数据集成平台 一、介绍1.1 企业级数据集成架构面临的痛点1.2 RestCloud说明1.3 重构企业数据融合架构&#xff0c;解决各种复杂、即时、高合规的数据集成需求1.4 (智能)全域数据集成平台1.5 300数据及应用连接器轻松汇聚全域数据 二、产品简介2.1 功能特性2.2 产…

Pytorch入门(五)使用ResNet-18网络训练常规状态下的CIFAR10数据集

本文采用ResNet-18PytorchCIFAR-10实现深度学习的训练。 文章目录 一、CIFAR-10 数据集介绍二、ResNet 神经网络的介绍1.ResNet 的网络模型2.本文用到的ResNet网络结构3.残差块的的解释4.ResNet神经网络的优缺点 三、ResNet-18 代码实现四、ResNet-18 训练 CIFAR-10数据集五、…

编写 OPC UA Compile的模型设计文件

OPC Foundation 开源了一个模型编译工具-UA ModelCompiler.它接受下面两种信息模型格式&#xff1a; NodeSet2.xmlModelDesign.xml 看来ModelDesign 是专门为UA ModelCompiler设计的&#xff0c;采用了分层结构描述&#xff0c;它比NodeSet2 可读性更好一点。适合使用普通文本…

【MySql】数据库的备份与恢复

文章目录 前言备份mysqldump还原source注意事项查看连接情况 前言 对与数据库的备份与恢复该怎么去做呢&#xff1f; Linux下对于文件或目录的备份&#xff0c;直接拷贝一份&#xff0c;留着备用&#xff0c;对于备份&#xff0c;比较简单的做法会就是直接打包拷贝一下&#x…

数据结构常用知识点整理(java版)(--修改中--)

目录 一、逻辑结构 1、栈 2、队列 顺序队列 循环队列 链式队列 &#xff08;相当于只能尾进头出的单链表&#xff09; 双端队列 (Deque) 3、数组 4、链表 5、树 二叉树 满二叉树 完全二叉树 二叉查找树&#xff1a; (ADT Tree) 红黑树&#xff1a; B树&#xf…

docker内无法通过域名访问外网问题解决方案一

一、问题描述 docker中有的时候需要从容器内向外网环境进行访问&#xff0c;这个时候我边出现了一个诡异的问题&#xff0c;从容器的宿主机直接通过curl命令使用域名可以正常的访问并返回正确的解决&#xff0c;但是从容器中向外调用外网环境的这个域名的时候&#xff0c;curl命…

ChatGPT 使用 拓展资料:吴恩达大咖 Building Systems with the ChatGPT API 内容审查

ChatGPT 使用 拓展资料:吴恩达大咖 Building Systems with the ChatGPT API 内容审查 https://learn.deeplearning.ai/chatgpt-building-system?_gl=114hjbho_gaMTEwNzkwNDAyMC4xNjgyNjUxMzg4_ga_PZF1GBS1R1*MTY4NTk2NTg1Ni4xNS4wLjE2ODU5NjU4NTYuNjAuMC4w 如果你正在建立一个…

糖酵解反应动力学方程的微分方程建模

糖酵解反应动力学方程的微分方程建模 题目 对于下面的糖酵解反应&#xff1a; 设其满足如下动力学方程&#xff1a; { d d t Glucose v 1 − v 2 d d t Gluc 6 P v 2 − v 3 d d t Fruc 6 P v 3 − v 4 v 5 d d t Fruc 1 , 6 P 2 v 4 − v 5 − v 6 d d t ATP −…

electron+vue3全家桶+vite项目搭建【19】集成微信登录

文章目录 引入实现思路实现步骤 引入 electron中实际就是嵌入了一个浏览器内核&#xff0c;所以在electron中集成微信登录实际和web端的集成方式是一样的。 demo项目地址 实现思路 这里参考这篇文章的 electron之微信扫码登陆&#xff08;不使用轮询&#xff09; 实现思路&a…

【数据结构】常见排序算法——常见排序介绍、选择排序(直接选择排序、堆排序)交换排序(冒泡排序)

文章目录 1.常见排序2.选择排序2.1直接选择排序2.2堆排序 3.交换排序3.1冒泡排序 1.常见排序 2.选择排序 选择排序是一种简单但不高效的排序算法&#xff0c;其基本思想是从待排序的数据中选择最小&#xff08;或最大&#xff09;的元素放到已排序的数据末尾。具体操作步骤如下…