QT网络(二):TCP通信

传输层概念

传输控制协议(transmission control protocol,TCP)是一种被大多数 Internet 网络协议用于数据传输的底层网络协议,它是可靠的、面向流和连接的传输协议,特别适合用于连续数据传输。

应用层在网络模型中的层次如下所示:

 传输层管理着端到端的通信,即主机到主机的通信。它的主要职责是为不同主机上的应用程序(占用不同端口)提供数据传输,同时保证这些数据的完整性和可靠性。

网络中还有一个IP协议概念,它与TCP的区分如下图所示:

IP协议属于网络层,是在TCP的报文基础上多了一个头部信息,例如在下列通信过程中,发送和接收的信息在每一层中通过该层的协议进行封包和拆包,最终实现通信。

通常IP层协议已经封装在操作系统中的IP协议栈中用于实现PC---PC的通信(这里的PC是不同的PC),开发QT应用程序时,实际上是PC上的进程,此时使用的是TCP和UDP,实现的是PC(A)----PC(B)的通讯(这里的PC可以是不同的PC,也可以是同一台PC,同一台时就是所谓的IPC主机内通信),A、B为计算机中的进程(可以理解为QT应用程序)。

TCP是面向连接的可靠传输协议,因此TCP 通信必须先建立 TCP 连接,通信端分为客 户端和服务器端Qt 提供 QTcpSocket 类和 QTcpServer 类,用于设计 TCP 通信应用程序。 服务器端程序必须使用 QTcpServer 进行端口监听,建立服务器;使用 QTcpSocket 建立连接,然后使用套接字(socket)进行通信。

相关的类介绍

QTcpServer类

QTcpServer 主要用于在服务器端进行网络监听,创建网络 socket 连接。该类提供的主要函数接口如下表所示,表中列出了函数的返回值,省略了函数的输入参数。

函数 listen()开始服务器端监听,可以设置监听的 IP 地址和端口,一般一个服务器端程序只监听某个端口的网络连接。

当有新的客户端接入时,QTcpServer 内部的函数 incomingConnection()会创建一个与客户端 连接的 QTcpSocket 对象,然后发射 newConnection()信号。在与 newConnection()信号关联的槽函数中,我们可以用 nextPendingConnection()接受客户端的连接,然后使用 QTcpSocket 对象与客户端通信。

所以最后数据通信是通过QTcpSocket类对象完成的,QTcpSocket 类提供了 TCP 的接口,可以用 QTcpSocket 类实现标准的网络通信协议,如 POP3、SMTP 和 NNTP 等(这些协议属于上层协议,也就是应用层),也可以设计自定义协议。

QTcpSocket类

由于 QTcpSocket继承了QAbstractSocket类,而QAbstractSocket又继承了QIODevice类,因此QTcpSocket是一种I/O类设备,具有流数据读写功能,其他大部分的功能函数都继承自QAbstractSocket类。QAbstractSocket类的主要接口函数如下表(省略了函数的输入参数)

TCP 客户端使用 QTcpSocket 对象与 TCP 服务器端建立连接并通信。客户端的 QTcpSocket 对象首先通过 connectToHost()尝试连接到服务器,该函数需要指定服务器的 IP 地址和端口。函数 connectToHost()以异步方式连接到服务器,不会阻塞程序运行,成功连接后 QTcpSocket 对象发 射 connected()信号。

客户端和服务器端建立 socket 连接后,各自的 QTcpSocket 对象就可以向缓冲区写数据或从接收缓冲区读取数据,实现数据通信。当缓冲区有新数据进入时,QTcpSocket 对象会发射readyRead() 信号,我们一般在此信号的槽函数里读取缓冲区数据。接收与发送是异步工作的,有各自的缓冲区。

TCP 服务器端程序设计

主窗口MainWindow头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include    <QTcpServer>
#include    <QLabel>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTprivate:QLabel  *labListen;         //状态栏标签QLabel  *labSocketState;    //状态栏标签QTcpServer *tcpServer;             //TCP服务器QTcpSocket *tcpSocket=nullptr;     //TCP通讯的SocketQString getLocalIP();              //获取本机IP地址
//protected:
//    void    closeEvent(QCloseEvent *event);   //close事件处理函数
public:MainWindow(QWidget *parent = nullptr);~MainWindow();      //析构函数里需要做一些处理,以保证断开与客户端的连接,并停止网络监听private slots://自定义槽函数void    do_newConnection();         //关联QTcpServer的newConnection()信号void    do_socketStateChange(QAbstractSocket::SocketState socketState);void    do_clientConnected();       //客户端 socket 已连接void    do_clientDisconnected();    //客户端 socket 已断开void    do_socketReadyRead();       //读取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 连接和通信。

在主窗口的构造函数中,首先获取本机IP地址并打印,然后创建TCP服务器QTcpServer 对象 tcpServer并将newConnection() 信号与自定义槽函数 do_newConnection()关联。

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); //创建TCP服务器connect(tcpServer,SIGNAL(newConnection()),this,SLOT(do_newConnection()));
}QString MainWindow::getLocalIP()
{//获取本机IPv4地址QString hostName=QHostInfo::localHostName();    //本地主机名QHostInfo hostInfo=QHostInfo::fromName(hostName);QString   localIP="";QList<QHostAddress> addList=hostInfo.addresses();  //本机IP地址列表if (addList.isEmpty())return localIP;foreach(QHostAddress aHost, addList)if (QAbstractSocket::IPv4Protocol==aHost.protocol()){//如果本机装有虚拟机软件,设置了VMnetx以太网适配器,可能会返回这些网络的地址localIP=aHost.toString();// break;qDebug()<<localIP<<Qt::endl;}return localIP;
}

获取本机IP地址使用往期博客讲解的localHostName()和fromName()来从主机名中获取了QHostInfo类型的对象,通过改对象的addresses()韩素华就可以获取本机IP地址列表,

这里需要注意的是,例程中直接返回了找到的第一个IPv4地址。如果有多个IPv4地址还需要根据其他条件判断来取舍。

在析构函数中,应确保窗口关闭时断开与 TCP 客户端的socket 连接,停止 TCP 服务器的网络监听。(先断开与客户端的连接,再停止监听)

MainWindow::~MainWindow()
{//析构函数if (tcpSocket != nullptr){if (tcpSocket->state()==QAbstractSocket::ConnectedState)tcpSocket->disconnectFromHost();    //断开与客户端的连接}if (tcpServer->isListening())tcpServer->close();     //停止网络监听delete ui;
}

开始监听

TCP服务器可以使用QTcpServer::listen()函数在本机某个 IP 地址和端口上开始 TCP监听,以等待 TCP 客户端的接入。对应“开始监听”按钮的槽函数如下:

void MainWindow::on_actStart_triggered()
{//"开始监听"按钮QString  IP=ui->comboIP->currentText();  //IP地址字符串,如"127.0.0.1"quint16  port=ui->spinPort->value();     //端口QHostAddress   address(IP);tcpServer->listen(address,port);    //开始监听//    tcpServer->listen(QHostAddress::LocalHost,port);// Equivalent to QHostAddress("127.0.0.1").ui->textEdit->appendPlainText("**开始监听...");ui->textEdit->appendPlainText("**服务器地址:"+tcpServer->serverAddress().toString());ui->textEdit->appendPlainText("**服务器端口:"+QString::number(tcpServer->serverPort()));ui->actStart->setEnabled(false);ui->actStop->setEnabled(true);labListen->setText("监听状态:正在监听");
}

函 数 listen()的原型定义如下:

bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0)

参数 address 是 QHostAddress 类型的主机地址,可以像程序中那样通过 IP 地址字符串创建 QHostAddress 对象。参数 port 是监听的端口号。

TCP监听本机的时候,可以使用本机地址127.0.0.1或常量 QHostAddress::LocalHost,抑或是

本机的实际 IP 地址。

与客户端建立sockect连接

tcpServer 开始监听后,TCP 客户端程序就可以通过 IP 地址和端口连接到此服务器。当有客户端 接入时,tcpServer 会发射 newConnection()信号。其槽函数槽函数 do_newConnection()对应的代码如下所示:

void MainWindow::do_newConnection()
{tcpSocket = tcpServer->nextPendingConnection(); //创建socketconnect(tcpSocket, SIGNAL(connected()),this, SLOT(do_clientConnected()));do_clientConnected();   //执行一次槽函数,显示状态connect(tcpSocket, SIGNAL(disconnected()),this, SLOT(do_clientDisconnected()));connect(tcpSocket,&QTcpSocket::stateChanged,this,&MainWindow::do_socketStateChange);do_socketStateChange(tcpSocket->state());   //执行一次槽函数,显示状态connect(tcpSocket,SIGNAL(readyRead()),  this,SLOT(do_socketReadyRead()));
}

程序通过QTcpServer::nextPendingConnection()函数获取与连接的客户端进行通信的 QTcpSocket 对象 tcpSocket,并将tcpSocket 的几个信号与相应的槽函数连接起来用于处理与客户端的通信。

服务器与客户端连接后tcpSocket会发射connected()信号,该信号的槽函数如下:

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

示例中用于打印相关状态。

服务器与客户端断开时,tcpSocket会发送disconnected()信号,该信号的槽函数如下:

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

当Sockect状态发生改变时,会发送stateChanged()信号,该信号对应的槽函数如下:

void MainWindow::do_socketStateChange(QAbstractSocket::SocketState socketState)
{//socket状态变化时switch(socketState){case QAbstractSocket::UnconnectedState:labSocketState->setText("socket状态:UnconnectedState");break;case QAbstractSocket::HostLookupState:labSocketState->setText("socket状态:HostLookupState");break;case QAbstractSocket::ConnectingState:labSocketState->setText("socket状态:ConnectingState");break;case QAbstractSocket::ConnectedState:labSocketState->setText("socket状态:ConnectedState");break;case QAbstractSocket::BoundState:labSocketState->setText("socket状态:BoundState");break;case QAbstractSocket::ClosingState:labSocketState->setText("socket状态:ClosingState");break;case QAbstractSocket::ListeningState:labSocketState->setText("socket状态:ListeningState");}
}

停止监听

TCP服务器停止监听

停止监听使用QTcpServer::close()函数,在停止监听前断开与客户端的连接,槽函数如下:

void MainWindow::on_actStop_triggered()
{//"停止监听"按钮if (tcpServer->isListening())   //tcpServer正在监听{if (tcpSocket != nullptr)if (tcpSocket->state()==QAbstractSocket::ConnectedState)tcpSocket->disconnectFromHost();tcpServer->close();         //停止监听ui->actStart->setEnabled(true);ui->actStop->setEnabled(false);labListen->setText("监听状态:已停止监听");}
}

与客户端数据通信

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

对于数据的传输有两种协议:基于行、基于块

基于行的数据通信协议一 般用于纯文本数据的通信,每一行数据以一个换行符结束。函数canReadLine()判断是否有新的一 行数据需要读取,如果有就可以用函数 readLine()读取一行数据。基于块的数据通信协议一般用于二进制数据的传输,需要自定义具体的格式。

示例程序中发送的是纯文本数据,使用的是基于行的传输模式,服务器向客户端发送消息如下:

void MainWindow::on_btnSend_clicked()
{//"发送消息"按钮,发送一行字符串,以换行符结束QString  msg=ui->editMsg->text();ui->textEdit->appendPlainText("[out] "+msg);ui->editMsg->clear();ui->editMsg->setFocus();QByteArray  str=msg.toUtf8();str.append('\n');       //添加一个换行符tcpSocket->write(str);
}

程序中将文本输入框中的QString类型字符串转换为QByteArray 类型的字节数组 str,然后在 str 最后面添加 一个换行符,用 QIODevice::write()函数将 str 写入缓冲区,这样就能向客户端发送一行文字。

当客户端发送数据时,服务器端缓冲区有新数据进入,QTcpSocket 对象会发射 readyRead()信号,该信号对应的槽函数是do_socketReadyRead(),一般在这个槽函数中进行接收数据的处理:

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

每当缓冲区数据攒够一行时(检测到换行符),就通过tcpSocket->readLine()获取一行数据。

TCP Server 通过上述方式与TCP Client 进行双向通信,且这个连接一直存在,直到某一方的 QTcpSocket 对象调用函数 disconnectFromHost()断开 socket 连接。

TCP客户端程序设计

主窗口设计

客户端主窗口与服务器窗口类似,头文件如下:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include    <QTcpSocket>
#include    <QLabel>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECT
private:QTcpSocket  *tcpClient;   //socketQLabel  *labSocketState;  //状态栏显示标签QString  getLocalIP();    //获取本机IP地址
public:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:
//自定义槽函数void    do_connected();void    do_disconnected();void    do_socketStateChange(QAbstractSocket::SocketState socketState);void    do_socketReadyRead();//读取socket传入的数据void on_actConnect_triggered();     //连接服务器void on_actDisconnect_triggered();  //断开服务器void on_actClear_triggered();       //清空文本框void on_btnSend_clicked();          //向服务器发送消息
private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

Mainwindow中也定义了一个用于 socket 连接和通信的 QTcpSocket 变量 tcpClient。在主窗口构造函数中,创建 tcpClient,并建立信号与槽函数的关联。相关槽函数与服务端器一致。

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();      //获取本机IPthis->setWindowTitle(this->windowTitle()+"----本机IP地址:"+localIP);ui->comboServer->addItem(localIP);connect(tcpClient,SIGNAL(connected()),   this,SLOT(do_connected()));connect(tcpClient,SIGNAL(disconnected()),this,SLOT(do_disconnected()));connect(tcpClient,&QTcpSocket::stateChanged,this,&MainWindow::do_socketStateChange);connect(tcpClient,SIGNAL(readyRead()),   this,SLOT(do_socketReadyRead()));
}void MainWindow::do_connected()
{ //connected()信号的槽函数ui->textEdit->appendPlainText("**已连接到服务器");ui->textEdit->appendPlainText("**peer address:"+tcpClient->peerAddress().toString());ui->textEdit->appendPlainText("**peer port:"+QString::number(tcpClient->peerPort()));ui->actConnect->setEnabled(false);ui->actDisconnect->setEnabled(true);
}void MainWindow::do_disconnected()
{//disConnected()信号的槽函数ui->textEdit->appendPlainText("**已断开与服务器的连接");ui->actConnect->setEnabled(true);ui->actDisconnect->setEnabled(false);
}void MainWindow::do_socketStateChange(QAbstractSocket::SocketState socketState)
{//stateChange()信号的槽函数switch(socketState){case QAbstractSocket::UnconnectedState:labSocketState->setText("socket状态:UnconnectedState");break;case QAbstractSocket::HostLookupState:labSocketState->setText("socket状态:HostLookupState");break;case QAbstractSocket::ConnectingState:labSocketState->setText("socket状态:ConnectingState");break;case QAbstractSocket::ConnectedState:labSocketState->setText("socket状态:ConnectedState");break;case QAbstractSocket::BoundState:labSocketState->setText("socket状态:BoundState");break;case QAbstractSocket::ClosingState:labSocketState->setText("socket状态:ClosingState");break;case QAbstractSocket::ListeningState:labSocketState->setText("socket状态:ListeningState");}
}void MainWindow::do_socketReadyRead()
{//readyRead()信号的槽函数while(tcpClient->canReadLine())ui->textEdit->appendPlainText("[in] "+tcpClient->readLine());
}

与服务器建立连接

客户端与服务建立连接,通过QTcpSocket::connectToHost()函数传入服务器地址和端口号,如果服务器此时处于监听状态就会成功建立连接。断开连接使用QTcpSocket::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();
}

与TCP服务器进行数据通信

和服务器一样,使用QTcpSocket类中提供的函数进行通信,代码部分完全一致:

void MainWindow::on_btnSend_clicked()
{//“发送数据”按钮QString  msg=ui->editMsg->text();ui->textEdit->appendPlainText("[out] "+msg);ui->editMsg->clear();ui->editMsg->setFocus();QByteArray  str=msg.toUtf8();str.append('\n');tcpClient->write(str);
}void MainWindow::do_socketReadyRead()
{//readyRead()信号的槽函数while(tcpClient->canReadLine())ui->textEdit->appendPlainText("[in] "+tcpClient->readLine());
}

小结

通过以上TCP服务器和客户端的程序设计可以看出,两者最大的不同部分是建立连接过程,服务器端通过listen()来主动打开监听,而客户端是通过connectToHost()主动连接服务器,其他部分基本都是一样的。

以上示例仅演示了TCP的基本通信,且是一对一的基于连接的通信,而在实际中的 TCP 服务器端程序允许多个客户端接入,为了使每个 socket 连接独立 通信、互不影响,一般采用多线程,即为一个 socket 连接创建一个线程。

参考

QT6 C++开发指南

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

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

相关文章

【记录50】uniapp安装uview插件,样式引入失败分析及解决

SassError: Undefined variable: "$u-border-color". 表示样式变量$u-border-color没定义&#xff0c;实际是定义的 首先确保安装了scss/sass 其次&#xff0c;根目录下 app.vue中是否全局引入 <style lang"scss">import /uni_modules/uview-ui/in…

TypeScript 与 JavaScript

文章目录 一、为 JavaScript 库添加类型定义(一)什么是类型定义文件(.d.ts 文件)(二)手动编写类型定义和使用现有类型定义(如 DefinitelyTyped)手动编写类型定义使用现有类型定义(如 DefinitelyTyped)二、在 TypeScript 项目中使用流行的 JavaScript 库(如 jQuery、…

算法—动态规划

一、简介 动态规划&#xff08;Dynamic Programming&#xff0c;简称 DP&#xff09;是一种通过将原问题分解为若干个子问题来求解最优化问题的算法思想。动态规划常常用于解决那些可以被分解为更小的重叠子问题的场景。 与分治法的区别在于&#xff0c;分治法会将问题分解成独…

Android GO 版本锁屏声音无效问题

问题描述 Android go版本 在设置中打开锁屏音开关&#xff0c;息屏灭屏还是无声音 排查 vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\keyguard\KeyguardViewMediator.java private void setupLocked() {...String soundPath Settings.G…

使用 NVIDIA DALI 计算视频的光流

引言 光流&#xff08;Optical Flow&#xff09;是计算机视觉中的一种技术&#xff0c;主要用于估计视频中连续帧之间的运动信息。它通过分析像素在时间维度上的移动来预测运动场&#xff0c;广泛应用于目标跟踪、动作识别、视频稳定等领域。 光流的计算传统上依赖 CPU 或 GP…

Tomcat的安装即使用

Tomcat的概念 Tomcat服务器是Java语言开发的&#xff0c;免费的开放源代码的Web应用服务器。 Tomcat处理静态HTML的能力远不及Apache或者Nginx&#xff0c;通常是作为一个Servlet和JSP容器&#xff0c;单独运行在后端。 Tomcat是由三个功能组合而成&#xff1a; java servlet&…

Linux:进程(环境变量、程序地址空间)

目录 冯诺依曼体系结构 操作系统 设计操作系统的目的 操作系统的管理 进程 PCB fork 进程状态 进程状态查看 僵尸进程 孤儿进程 进程优先级 查看、修改进程优先级命令 竞争、独立、并行、并发 进程切换 活动队列和运行队列 活动队列 过期队列 active指针…

对于使用exe4j打包,出现“NoClassDefFoundError: BOOT-INF/classes”的解决方案

jar使用exe4j打包exe&#xff0c;出现NoClassDefFoundError: BOOT-INF/classes 注意选取的jar包是使用build&#xff0c;而不是maven中的install 本文介绍解决这个方法的方案 点击Project Structure 按照如图所示选择 选择main class&#xff0c;选择你要打的main 如果遇到/M…

uniapp连接蓝牙操作(蓝牙设备地锁)

介绍&#xff1a; 本文采用uni-app框架来创建一个简单的用户界面&#xff0c;用于搜索、连接和发送命令给蓝牙设备。 1.打开蓝牙适配器 function openBluetooth() {uni.openBluetoothAdapter({success() {uni.offBluetoothDeviceFound();// 监听新设备发现事件uni.onBlueto…

web:pc端企业微信登录-vue版

官方文档&#xff1a;developer.work.weixin.qq.com/document/pa… 不需要调用ww.register&#xff0c;直接调用ww.createWWLoginPanel即可创建企业微信登录面板 - 文档 - 企业微信开发者中心 (qq.com) 引入 //通过 npm 引入 npm install wecom/jssdk import * as ww from we…

外观模式的理解和实践

外观模式&#xff08;Facade Pattern&#xff09;是一种常用的软件设计模式&#xff0c;它提供了一个统一的接口&#xff0c;用来访问子系统中的一群接口。该模式定义了一个高层的接口&#xff0c;使得子系统更容易使用。简单来说&#xff0c;外观模式就是通过引入一个外观角色…

《应用导航设计:裂变式路由风暴来袭》——HarmonyOS开发项目时的Navigation路由奇妙使用

文章目录 应用导航设计引言概述场景示例基本实现推荐方案路由管理模块的实现页面跳转实现 业务实现中的关键点动态加载路由栈管理 应用导航设计 引言 在大型应用开发中&#xff0c;如何高效地设计应用导航&#xff0c;处理多模块间的路由跳转与解耦&#xff0c;始终是一个关键…

【腾讯云】AI驱动TDSQL-C Serveress 数据库技术实战营-如何是从0到1体验电商可视化分析小助手得统计功能,一句话就能输出目标统计图

欢迎来到《小5讲堂》 这是《腾讯云》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景效果图流程图创建数据库基本信息数据库配置设置密码控制台开启…

win服务器的架设、windows server 2012 R2 系统的下载与安装使用

文章目录 windows server 2012 R2 系统的下载与安装使用1 windows server 2012 的下载2 打开 VMware 虚拟机软件&#xff08;1&#xff09;新建虚拟机&#xff08;2&#xff09;设置虚拟机&#xff08;3&#xff09;打开虚拟机 windows server 2012&#xff08;4&#xff09;进…

如何在谷歌浏览器中开启安全浏览

在数字化时代&#xff0c;网络安全变得愈发重要。作为全球最受欢迎的网络浏览器之一&#xff0c;谷歌浏览器提供了多种功能来保护用户的在线安全。本文将详细介绍如何在谷歌浏览器中开启安全浏览&#xff0c;并额外提供一些有用的页面滚动设置、地址栏快捷搜索和跟踪防护的相关…

djiango DRF的使用

djiango DRF的使用 一 、初始 DRF序列化环境安装环境配置数据模型定义定义DRF序列化模型对象 二 、DRF请求和响应请求对象&#xff08;Request objects&#xff09;响应对象&#xff08;Response objects&#xff09;状态码&#xff08;Status codes&#xff09;包装&#xff0…

计算机网络-HTTP协议

HTTP HTTP是一种不保存状态&#xff0c;即无状态的协议。HTTP协议自身不对请求和响应之间的通信进行保存。为了保存状态因此后面也有一些技术产生比如Cookies技术。 HTTP是通过URI定位网上的资源&#xff0c;理论上将URI可以访问互联网上的任意资源。 如果不是访问特定的资源…

CTFHub 命令注入-综合练习(学习记录)

综合过滤练习 命令分隔符的绕过姿势 ; %0a %0d & 那我们使用%0a试试&#xff0c;发现ls命令被成功执行 /?ip127.0.0.1%0als 发现一个名为flag_is_here的文件夹和index.php的文件&#xff0c;那么我们还是使用cd命令进入到文件夹下 http://challenge-438c1c1fb670566b.sa…

【AI知识】逻辑回归介绍+ 做二分类任务的实例(代码可视化)

1. 分类的基本概念 在机器学习的有监督学习中&#xff0c;分类一种常见任务&#xff0c;它的目标是将输入数据分类到预定的类别中。具体来说&#xff1a; 分类任务的常见应用&#xff1a; 垃圾邮件分类&#xff1a;判断一封电子邮件是否是垃圾邮件 。 医学诊断&#xff1a;…

为SSH2协议服务器的用户设置密钥

目录 私钥的创建1. 在服务器上直接生成2. 如果需要配置免密登录3. 查看生成的密钥 导出私钥至SSH用户获取sudo权限 新的一台服务器类型是SSH2&#xff1a;这表示服务器支持SSH&#xff08;Secure Shell&#xff09;协议的第二个版本。SSH是一个网络协议&#xff0c;用于加密方式…