Qt基础 | TCP通信 | TCP服务端与客户端程序设计 | QTcpServer | QTcpSocket

news2024/11/26 5:35:53

文章目录

  • 一、TCP 通信
    • 1.TCP 通信概述
    • 2.TCP 服务器端程序设计
      • 2.1 主窗口定义与构造函数
      • 2.2 网络监听与 socket 连接的建立
      • 2.3 与 TCP 客户端进行数据通信
    • 3.TCP 客户端程序设计
      • 3.1 主窗口定义与构造函数
      • 3.2 与服务器端建立 socket 连接
      • 3.3 与 TCPServer 的数据收发
    • 4.小结


Qt 网络模块:

  • Qt基础 | 主机信息查询 | QHostInfo的介绍和使用 | QNetworkInterface的介绍和使用

  • Qt基础 | TCP通信 | TCP服务端与客户端程序设计 | QTcpServer | QTcpSocket

  • Qt基础 | UDP通信 | UDP单播、广播、组播的介绍与实现

  • Qt基础 | 基于HTTP协议的网络文件下载


一、TCP 通信

1.TCP 通信概述

   TCP 是一种被大多数 Internet 网络协议(如 HTTP 和 FTP) 用于数据传输的低级网络协议,它是可靠的、面向流 、面向连接的传输协议,特别适合用于连续数据传输。

  TCP 通信必须先建立 TCP 连接,通信端分为客户端和服务器端。Qt 提供 QTcpSocket 类和 QTcpServer 类用于建立 TCP 通信应用程序。服务器端程序必须使用 QTcpServer 用于端口监听,建立服务器;QTcpSocket 用于建立连接后使用套接字(Socket)进行通信。

image-20240730120301893

  QTcpServer 是从 QObject 继承的类,它主要用于服务器端建立网络监听,创建网络 Socket 连接。

  服务器端程序首先需要用 QTcpServer::listen() 开始服务器端监听,可以指定监听的 IP 地址和端口,一般一个服务程序只监听某个端口的网络连接。当有新的客户端接入时,QTcpServer内部的 incomingConnection() 函数会创建一个与客户端连接的 QTcpSocket 对象,并添加到内部可用新连接列表,然后发射 newConnection() 信号。在 该信号的槽函数中,可以用 nextPendingConnection() 函数接受客户端的连接,然后使用 QTcpSocket 与客户端通信。在客户端与服务器建立 TCP 连接后,具体的数据通信是通过 QTcpSocket 完成的。

QTcpServer 类的主要接口函数

image-20240730120510179

  QTcpSocket 类是从 QIODevice 间接继承的类,所以具有流数据读写的功能。一个 QTcpSocket 实例既可以接收数据也可以发送数据,且接收与发射是异步工作的,有各自的缓冲区。QTcpSocket 类除了构造函数和析构函数,其他函数都是从 QAbstractSocket 继承或重定义的。

  TCP 客户端使用 QTcpSocket 与 TCP 服务器建立连接并通信。客户端的 QTcpSocket 实例首先通过 connectToHost() 尝试连接到服务器,需要指定服务器的 IP 地址和端口。connectToHost() 以异步方式连接服务器,即以非阻塞程序运行,connectToHost() 成功连接到服务器发射 connected() 信号。如果需要使用阻塞方式连接服务器,则使用 waitForConnected() 函数阻塞程序运行,直到建立 socket 连接。与服务器端建立 socket 连接后,就可以向缓冲区写数据或从接收缓冲区读取数据,实现数据的通信。当缓冲区有新数据进入时 会发射 readyRead() 信号,一般在此信号的槽函数里读取缓冲区数据。

QAbstractSocket 用于 TCP 通信的主要接口函数

image-20240730121919073

2.TCP 服务器端程序设计

TCP 服务器端程序应具有以下功能

  • 根据指定 IP 地址和端口打开网络监听,有客户端连接时创建 socket 连接
  • 采用基于行的数据通信协议,可以接收客户端发来的消息,也可以向客户端发送消息
  • 在状态栏显示服务器监听状态和 socket 的状态

2.1 主窗口定义与构造函数

   TCPServer 是一个基于 QMainWindow 的应用程序,界面是由 UI 设计器设计,设计如下:

image-20240730133815816

  主窗口类 MainWindow 定义如下:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include    <QTcpServer>
#include    <QLabel>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

private:
    QLabel  *LabListen;//状态栏标签
    QLabel  *LabSocketState;//状态栏标签
    QTcpServer *tcpServer; //TCP服务器
    QTcpSocket *tcpSocket;//TCP通讯的Socket

    QString getLocalIP();//获取本机IP地址

protected:
    void    closeEvent(QCloseEvent *event);

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
//自定义槽函数
    void    onNewConnection();//QTcpServer的newConnection()信号

    void    onSocketStateChange(QAbstractSocket::SocketState socketState);
    void    onClientConnected(); //Client Socket connected
    void    onClientDisconnected();//Client Socket disconnected
    void    onSocketReadyRead();//读取socket传入的数据
//UI生成的
    void on_actStart_triggered();
    void on_actStop_triggered();
    void on_actClear_triggered();
    void on_btnSend_clicked();
    void on_actHostInfo_triggered();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

私有变量:

  • tcpServer:用于建立 TCP 服务器
  • tcpSocket:用于与客户端进行 socket 连接和通信。
  • LabListen:用于显示服务器监听状态
  • LabSocketState:用于显示 socket 的状态

槽函数:

  • onNewConnection()函数:

    当有新客户端接入时,会发射 newConnection()信号,连接到该槽函数,在该槽函数中可以调用 nextPendingConnection() 函数获取与接入连接进行通信的 socket,然后将 socket 的几个信号与相应的槽函数连接起来。

  • onClientConnected()函数:

    当 tcpSocket 与服务器连接建立时,发射 connected() 信号,连接到该槽函数。

  • onClientDisconnected()函数:

    当 tcpSocket 与服务器连接断开时,发射 disconnected() 信号,连接到该槽函数。

  • onSocketStateChange()函数:

    当 tcpSocket 状态发生变化时,发射 stateChanged() 信号,连接到该槽函数。

  • onSocketReadyRead()函数:

    当 tcpSocket 发射 readyRead() 信号时,连接到该槽函数。

构造函数

  构造函数创建状态栏上的标签用于信息显示,调用自定义函数 getLocalIP()获取本机 IP 地址,并显示到标题栏上。创建 QTcpServer 实例 tcpServer,并将其 newConnection() 信号与 onNewConnection() 槽函数关联。

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

    LabListen=new QLabel("监听状态:");
    LabListen->setMinimumWidth(150);
    ui->statusBar->addWidget(LabListen);

    LabSocketState=new QLabel("Socket状态:");//
    LabSocketState->setMinimumWidth(200);
    ui->statusBar->addWidget(LabSocketState);

    QString localIP=getLocalIP();//本机IP
    this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);
    ui->comboIP->addItem(localIP);

    tcpServer=new QTcpServer(this);
    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
}

QString MainWindow::getLocalIP()
{//获取本机IPv4地址
    QString hostName=QHostInfo::localHostName();//本地主机名
    QHostInfo   hostInfo=QHostInfo::fromName(hostName);
    QString   localIP="";

    QList<QHostAddress> addList=hostInfo.addresses();//

    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;
}

2.2 网络监听与 socket 连接的建立

网络监听

  作为 TCP 服务器,QTcpServer 类需要调用 listen() 函数在本机某个 IP 地址和端口上开始 TCP 监听,以等待 TCP 客户端的接入。单击 “开始监听” 按钮,会触发槽函数,代码如下:

void MainWindow::on_actStart_triggered()
{//开始监听
    QString     IP=ui->comboIP->currentText();//IP地址
    quint16     port=ui->spinPort->value();//端口
    QHostAddress    addr(IP);
    tcpServer->listen(addr,port);//
//    tcpServer->listen(QHostAddress::LocalHost,port);// Equivalent to QHostAddress("127.0.0.1").
    ui->plainTextEdit->appendPlainText("**开始监听...");
    ui->plainTextEdit->appendPlainText("**服务器地址:"
                       +tcpServer->serverAddress().toString());
    ui->plainTextEdit->appendPlainText("**服务器端口:"
                       +QString::number(tcpServer->serverPort()));

    ui->actStart->setEnabled(false);
    ui->actStop->setEnabled(true);

    LabListen->setText("监听状态:正在监听");
}
  • IP 地址可以是表示本机的 “127.0.0.1”,或是本机的实际 IP 地址。

socket 连接的建立

  tcpServer 开始监听后,TCPClient 就可以通过 IP 地址和端口连接到此服务器。当有客户端接入时, tcpServer 会发射 newConnection() 信号,此信号关联到 onNewConnection()槽函数。在该槽函数中可以调用 nextPendingConnection() 函数获取与接入连接进行通信的 socket,然后将 socket 的几个信号与相应的槽函数连接起来。代码如下:

void MainWindow::onNewConnection()
{
//    ui->plainTextEdit->appendPlainText("有新连接");
    tcpSocket = tcpServer->nextPendingConnection(); //创建socket

    connect(tcpSocket, SIGNAL(connected()),
            this, SLOT(onClientConnected()));
    onClientConnected();//

    connect(tcpSocket, SIGNAL(disconnected()),
            this, SLOT(onClientDisconnected()));

    connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    onSocketStateChange(tcpSocket->state());

    connect(tcpSocket,SIGNAL(readyRead()),
            this,SLOT(onSocketReadyRead()));
}

  QTcpSocket 的这几个信号的作用是:

  • connected()信号,客户端 socket 连接建立时发射此信号
  • disconnected() 信号,客户端 socket 连接断开时发射此信号
  • stateChanged() 信号,socket 状态变化时发射此信号
  • readyRead() 信号,socket 的读取缓冲区有新数据时发射此信号

这几个信号对应的槽函数如下:

void MainWindow::onClientConnected()
{//客户端接入时
    ui->plainTextEdit->appendPlainText("**client socket connected");
    ui->plainTextEdit->appendPlainText("**peer address:"+
                                   tcpSocket->peerAddress().toString());
    ui->plainTextEdit->appendPlainText("**peer port:"+
                                   QString::number(tcpSocket->peerPort()));
}

void MainWindow::onClientDisconnected()
{//客户端断开连接时
    ui->plainTextEdit->appendPlainText("**client socket disconnected");
    tcpSocket->deleteLater();
    //    deleteLater();//QObject::deleteLater();
}

void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{//socket状态变化时
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState:
        LabSocketState->setText("scoket状态:UnconnectedState");
        break;
    case QAbstractSocket::HostLookupState:
        LabSocketState->setText("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ConnectingState:
        LabSocketState->setText("scoket状态:ConnectingState");
        break;

    case QAbstractSocket::ConnectedState:
        LabSocketState->setText("scoket状态:ConnectedState");
        break;

    case QAbstractSocket::BoundState:
        LabSocketState->setText("scoket状态:BoundState");
        break;

    case QAbstractSocket::ClosingState:
        LabSocketState->setText("scoket状态:ClosingState");
        break;

    case QAbstractSocket::ListeningState:
        LabSocketState->setText("scoket状态:ListeningState");
    }
}

void MainWindow::onSocketReadyRead()
{//读取缓冲区行文本
    while(tcpSocket->canReadLine())
        ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine());
}

停止监听

  TCP 服务器停止监听,只需调用 QTcpServer 的 close () 函数即可。单击 “停止监听” 按钮,其响应槽函数代码如下:

void MainWindow::on_actStop_triggered()
{//停止监听
    if (tcpServer->isListening()) //tcpServer正在监听
    {
        tcpServer->close();//停止监听
        ui->actStart->setEnabled(true);
        ui->actStop->setEnabled(false);
        LabListen->setText("监听状态:已停止监听");
    }
}

2.3 与 TCP 客户端进行数据通信

  TCP 服务器端和客户端之间通过 QTcpSocket 通信时,需要规定两者之间的通信协议,即传输的数据内容如何解析。 QTcpSocket 间接继承于 QIODevice,所以支待流读写功能。

  Socket 之间的数据通信协议一般有两种方式:基于行的或基于数据块的

  • 基于行的数据通信协议一般用于纯文本数据的通信,每一行数据以一个换行符结束。一般是通过调用 canReadLine() 函数判断是否有新的一行数据需要读取,再调用 readLine() 函数读取一行数据,例如:

    //读取缓冲区行文本
    while(tcpSocket->canReadLine())
         ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine());
    
  • 基于块的数据通信协议用于一般的二进制数据的传输,需要自定义具体的格式。

发送数据

  将输入文本框中的字符串转换为 QByteArray 类型的字节数组,然后调用 QIODevice 的 write() 函数写入缓冲区,这样就完成向客户端发送一行文字。单击 “发送信息” 按钮,会触发上述内容,代码如下:

void MainWindow::on_btnSend_clicked()
{//发送一行字符串,以换行符结束
    QString  msg=ui->editMsg->text();
    ui->plainTextEdit->appendPlainText("[out] "+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();

    QByteArray  str=msg.toUtf8();
    str.append('\n');//添加一个换行符
    tcpSocket->write(str);
}

读取数据

  QTcpSocket 接收到来自客户端的数据后,会发射 readyRead() 信号,在其槽函数中需要读取行缓冲区的数据。代码如下:

void MainWindow::onSocketReadyRead()
{//读取缓冲区行文本
    while(tcpSocket->canReadLine())
        ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine());
}

这样,TCPServer 就可以与 TCPClient 之间进行双向通信了,且这个连接将一直存在,直到某一方的 QTcpSocket 对象调用 disconnectFromHost() 函数断开 socket 连接。

运行效果图:

image-20240730150454758

3.TCP 客户端程序设计

  客户端程序 TCPClient 只需要使用一个 QTcpSocket 对象,就可以和服务器端程序 TCPServer 进行通信。

TCP 客户端程序应具有以下功能

  • 通过 IP 地址和端口号连接到服务器
  • 采用基于行的数据通信协议,与服务器端收发消息
  • 处理 QTcpSocket 的 StateChange() 信号,在状态栏显示 socket 的状态

3.1 主窗口定义与构造函数

   TCPClient 是一个基于 QMainWindow 的应用程序,界面是由 UI 设计器设计,设计如下:

image-20240730144529288

  主窗口定义如下:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include    <QTcpSocket>
#include    <QLabel>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
private:
    QTcpSocket  *tcpClient;  //socket
    QLabel  *LabSocketState;  //状态栏显示标签

    QString getLocalIP();//获取本机IP地址
protected:
    void    closeEvent(QCloseEvent *event);
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
//自定义槽函数
    void    onConnected();
    void    onDisconnected();
    void    onSocketStateChange(QAbstractSocket::SocketState socketState);
    void    onSocketReadyRead();//读取socket传入的数据
//
    void on_actConnect_triggered();
    void on_actDisconnect_triggered();
    void on_actClear_triggered();
    void on_btnSend_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

私有变量:

  • tcpClient:用于socket 连接与通信
  • LabSocketState:用于显示 socket 状态

槽函数:自定义了几个槽函数,用于与 tcpClient 的相关信号关联。

构造函数

  构造函数主要功能是创建 tcpClient,设置状态栏标签,往下拉列表组件中添加本机 IP,最后建立信号与槽函数的关联。

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

    tcpClient=new QTcpSocket(this); //创建socket变量

    LabSocketState=new QLabel("Socket状态:");//状态栏标签
    LabSocketState->setMinimumWidth(250);
    ui->statusBar->addWidget(LabSocketState);

    QString localIP=getLocalIP();//本机IP
    this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);
    ui->comboServer->addItem(localIP);


    connect(tcpClient,SIGNAL(connected()),this,SLOT(onConnected()));
    connect(tcpClient,SIGNAL(disconnected()),this,SLOT(onDisconnected()));

    connect(tcpClient,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    connect(tcpClient,SIGNAL(readyRead()),
            this,SLOT(onSocketReadyRead()));
}

3.2 与服务器端建立 socket 连接

  通过调用 QTcpSocket 的函数 connectToHost() 连接到服务器,也可以使用 disconnectFromHost() 函数断开与服务器的连接。其代码如下:

void MainWindow::on_actConnect_triggered()
{//连接到服务器
    QString     addr=ui->comboServer->currentText();
    quint16     port=ui->spinPort->value();
    tcpClient->connectToHost(addr,port);
//    tcpClient->connectToHost(QHostAddress::LocalHost,port);
}

void MainWindow::on_actDisconnect_triggered()
{//断开与服务器的连接
    if (tcpClient->state()==QAbstractSocket::ConnectedState)
        tcpClient->disconnectFromHost();
}

void MainWindow::onConnected()
{ //connected()信号槽函数
    ui->plainTextEdit->appendPlainText("**已连接到服务器");
    ui->plainTextEdit->appendPlainText("**peer address:"+
                                   tcpClient->peerAddress().toString());
    ui->plainTextEdit->appendPlainText("**peer port:"+
                                   QString::number(tcpClient->peerPort()));
    ui->actConnect->setEnabled(false);
    ui->actDisconnect->setEnabled(true);
}

void MainWindow::onDisconnected()
{//disConnected()信号槽函数
    ui->plainTextEdit->appendPlainText("**已断开与服务器的连接");
    ui->actConnect->setEnabled(true);
    ui->actDisconnect->setEnabled(false);
}

3.3 与 TCPServer 的数据收发

  TCPClient 与 TCPServer 之间采用基于行的数据通信协议。

发送数据

  将输入文本框中的字符串转换为 QByteArray 类型的字节数组,然后调用 QIODevice 的 write() 函数写入缓冲区,这样就完成向服务器端发送一行文字。单击 “发送信息” 按钮,会触发上述内容,代码如下:

void MainWindow::on_btnSend_clicked()
{//发送数据
    QString  msg=ui->editMsg->text();
    ui->plainTextEdit->appendPlainText("[out] "+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();

    QByteArray  str=msg.toUtf8();
    str.append('\n');
    tcpClient->write(str);
}

接收数据

  QTcpSocket 接收到来自服务器端的数据后,会发射 readyRead() 信号,在其槽函数中需要读取行缓冲区的数据。代码如下:

void MainWindow::onSocketReadyRead()
{//readyRead()信号槽函数
    while(tcpClient->canReadLine())
        ui->plainTextEdit->appendPlainText("[in] "+tcpClient->readLine());
}

运行结果:

image-20240730150519960

4.小结

  上述客户端与服务端程序只是为了演示 TCP 通信的基本原理,TCPServer 只允许一个TCPClient 客户端接入。而一般的 TCP 服务器程序允许多个客户端接入,为了使每个 socket 连接独立通信互不影响,一般采用多线程 ,即为一个 socket 连接创建一个线程。

  上述的数据通信采用基于行的通信协议,这种 socket 通信方式只能传输字符串数据。QTcpSocket 间接继承于 QIODevice,可以使用数据流的方式传输二进制数据流,例如传输图片、任意格式文件等,但是这涉及到服务器端和客户端之间通信协议的定义。

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

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

相关文章

[Docker][Docker Image]详细讲解

目录 1.Docker镜像是什么&#xff1f;2.Docker镜像加载原理1.bootfs2.rootfs3.为什么CentOS镜像几个G&#xff0c;而Docker CentOS镜像才几百M&#xff1f;1.CentOS2.Docker CentOS 3.镜像分层1.Union FS2.分层理解3.容器层 vs 镜像层 4.镜像命令1.docker images2.docker image…

大数据信用报告查询会不会留下查询记录?怎么选择查询平台?

最近有不少网友都在咨询一个问题&#xff0c;那就是大数据信用报告查询会不会留下查询记录&#xff0c;会不会对自己的征信产生影响&#xff0c;下面本文就详细为大家介绍一下&#xff0c;希望对你了解大数据信用有帮助。 首先、大数据信用与人行征信是独立的 很多人只知道人行…

innovus:如何only select highlighted

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 来自星球提问&#xff1b; 1&#xff09;ICC2 2&#xff09;innovus View->Set Preference&#xff0c;勾选Only Select Highlighted

新装centos7虚拟机如何配置网络,NAT配置固定IP

首先声明&#xff0c;我想使用的是NAT连接模式&#xff0c;并且设置完IP之后&#xff0c;使得这个IP固定住&#xff0c;以后不会再变了。 文章目录 1&#xff0c;打开Vmware软件的【编辑】-【虚拟网络编辑器】2&#xff0c;先选择VMnet8&#xff08;画1处&#xff09;&#xf…

2025上海国际显示技术及应用创展览会

DIC EXPO2025中国&#xff08;上海&#xff09;国际显示技术及应用创展览会 时间&#xff1a;2025年8月7-9日 地点&#xff1a;上海新国际博览中心 主办单位&#xff1a; 中国光学光电子行业协会液晶分会 联合主办&#xff1a; 中国电子材料行业协会 中国电子商会 韩国…

嵌入式人工智能(32-基于树莓派4B的旋转编码器-EnCoder11)

1、旋转编码器 旋转编码器是一种输入设备&#xff0c;通常用于测量和控制旋转运动。它由一个旋转轴和一系列编码器组成。旋转编码器可以根据旋转轴的位置和方向来测量旋转角度&#xff0c;并将其转化为电子信号输出。 旋转编码器通常分为两种类型&#xff1a;绝对值编码器和增…

【微服务】Spring Cloud Gateway

文章目录 强烈推荐引言主要功能关键概念示例配置依赖添加常见的几种整合案例1. 与 Spring Cloud Eureka 整合2. 与 Spring Cloud Config 整合3. 与 Spring Cloud Sleuth 和 Zipkin 整合4. 与 Spring Cloud Security 整合5. 与 Resilience4j 整合6. 与 Redis 整合 结论强烈推荐专…

Matlab编程资源库(19)级数与符号方程求解

一、级数符号求和 求无穷级数的和需要 符号表达式求和函数 symsum &#xff0c;其调用 格式为&#xff1a; symsum(s,v,n,m) 其中 s 表示一个级数的通项&#xff0c;是一个符号表达式。 v 是求和变 量&#xff0c; v 省略时使用系统的默认变量。 n 和 m 是求和的开始项 和…

如何恢复WPS文档中未保存或删除的文件

由于各种原因&#xff0c;您可能会丢失 WPS 文档&#xff0c;例如意外删除、硬盘格式化、病毒攻击等。您是否遇到过丢失未保存的 WPS 文件的情况&#xff1f;您知道如何恢复 WPS 文档中未保存的文件吗&#xff1f; WPS Office 是一款办公套件&#xff0c;可以作为 Microsoft O…

火山引擎VeDI数据技术分享:两个步骤,为Parquet降本提效

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 作者&#xff1a;王恩策、徐庆 火山引擎 LAS 团队 火山引擎数智平台 VeDI 是火山引擎推出的新一代企业数据智能平台&#xff0c;基于字节跳动数据平台多年的“数据…

一个私有化的中文笔记工具个人知识库,极空间Docker部署中文版『Trilium Notes』

一个私有化的中文笔记工具&个人知识库&#xff0c;极空间Docker部署中文版『Trilium Notes』 哈喽小伙伴们好&#xff0c;我是Stark-C~ 最近被很多小伙伴问到NAS上的笔记工具&#xff0c;虽说之前也出过Memos&#xff0c;刚开始用起来还不错&#xff0c;但是用了一段时间…

W1R3S靶机全通详细教程

文章目录 w1r3s主机发现主机扫描 端口扫描tcp端口扫描UDP扫描漏洞扫描 攻击面分析FTP渗透匿名登录 web渗透目录爆破 cuppa cms文件包含漏洞getshell提权 w1r3s 引言 近些日子看红笔大佬的靶机精讲视频时&#xff0c;他的一句话让我感受颇深&#xff0c;很多视频在讲解时&…

《Windows API每日一练》23.1 Windows多媒体

本节我们将讲述单线程到多线程的演进过程&#xff0c;以及进程与线程的区别。 本节必须掌握的知识点&#xff1a; 多媒体硬件 API 概述 第172练&#xff1a;交互输入MCI命令 23.1.1多媒体硬件 多媒体硬件是指用于处理音频、视频和其他多媒体内容的硬件设备。在计算机系统中&…

迈尔沃护眼大路灯怎么样?书客、迈尔沃、霍尼韦尔护眼灯测评PK!

迈尔沃护眼大路灯怎么样&#xff1f;作为一名专业的实测博主&#xff0c;温馨提示大家&#xff0c;虽然护眼落地灯是个好东西&#xff0c;它能够提供柔和舒适的环境光&#xff0c;减少对眼睛的伤害&#xff0c;但是千万别乱买跟风&#xff0c;盲目入手踩雷率80%以上。那么如何辨…

SpringBoot集成 Druid 连接池及监控配置详解

Spring Boot 集成 Druid 连接池及监控配置详解 Spring Boot 是当前 Java 开发中的热门框架&#xff0c;而在数据库连接池的选择上&#xff0c;Druid 因其性能和功能强大也备受青睐。在这篇文章中&#xff0c;我们将深入探讨如何在 Spring Boot 项目中集成 Druid 连接池&#x…

大厂linux面试题攻略二之Linux系统管理

一、Linux系统管理权限优化类 1.简述Linux权限划分原则&#xff08;经验类&#xff09; 文件权限&#xff1a; 默认权限&#xff1a; 特殊权限; ACL权限&#xff1a; sudo授权&#xff1a; 文件系统属性权限&#xff1a; 解题思路&#xff1a; 注意权限分离(Linux系统…

入门 PyQt6 看过来(案例)17~ 表格

PyQt6提供了两种用于有规律地呈现更多数据的控件&#xff0c;一种是表格结构的控件(QTableView)&#xff0c;另一种是树形结构的控件(QTreeView)。表格控件属于QTableView类&#xff0c;QTableWidget继承于QTableView。 1 QTableView 表格控件 QTableView控件中QStandItemMod…

安胜:促进数据跨境有序流动 赋能企业数字化转型

数字化转型浪潮中&#xff0c;数据出境面临众多机遇与挑战。从业务角度&#xff0c;经济全球化推动外商投资、跨境业务等业务合作&#xff0c;企业数据跨境流动需求强烈&#xff0c;但数据违规现象频发&#xff0c;不仅导致巨大经济损失&#xff0c;还挑战了国家安全。从监管层…

什么是 HTTP/3?HTTP/3 为何席卷全球?HTTP/3 中有什么新内容?为什么需要它?

超文本传输​​协议 ( HTTP ) 是互联网的基石&#xff0c;有助于加载网页、流式传输视频以及为您最喜爱的应用程序获取数据。 去年 &#xff0c;负责定义互联网技术的组织 互联网工程任务组 ( IETF )对该协议的新版本 HTTP/3 进行了标准化。自那时起&#xff0c;HTTP/3 和相关…

KubeSphere 部署向量数据库 Milvus 实战指南

作者&#xff1a;运维有术星主 Milvus 是一个为通用人工智能&#xff08;GenAI&#xff09;应用而构建的开源向量数据库。它以卓越的性能和灵活性&#xff0c;提供了一个强大的平台&#xff0c;用于存储、搜索和管理大规模的向量数据。Milvus 能够执行高速搜索&#xff0c;并以…