《十六》QT TCP协议工作原理和实战

news2024/11/28 8:51:32

        Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QTcpSocket组件实现基于TCP的网络通信功能。

   QTcpSocketQTcpServer是Qt中用于实现基于TCP(Transmission Control Protocol)通信的两个关键类。TCP是一种面向连接的协议,它提供可靠的、双向的、面向字节流的通信。这两个类允许Qt应用程序在网络上建立客户端和服务器之间的连接。

以下是QTcpSocket类的一些常用函数:

函数描述
QTcpSocket()构造函数,创建一个新的QTcpSocket对象。
~QTcpSocket()析构函数,释放QTcpSocket对象及其资源。
void connectToHost(const QString &hostName, quint16 port)尝试与指定主机名和端口建立连接。
void disconnectFromHost()断开与主机的连接。
QAbstractSocket::SocketState state() const返回套接字的当前状态。
QHostAddress peerAddress() const返回与套接字连接的远程主机的地址。
quint16 peerPort() const返回与套接字连接的远程主机的端口。
QAbstractSocket::SocketError error() const返回套接字的当前错误代码。
qint64 write(const char *data, qint64 maxSize)将数据写入套接字,返回实际写入的字节数。
qint64 read(char *data, qint64 maxSize)从套接字读取数据,返回实际读取的字节数。
void readyRead()当套接字有可供读取的新数据时发出信号。
void bytesWritten(qint64 bytes)当套接字已经写入指定字节数的数据时发出信号。
void error(QAbstractSocket::SocketError socketError)当套接字发生错误时发出信号。

以下是QTcpServer类的一些常用函数及其简要解释:

函数   

描述
QTcpServer()  构造函数,创建一个新的QTcpServer对象。
~QTcpServer()   析构函数,释放QTcpServer对象及其资源。
bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0)    开始监听指定的地址和端口。
void close()     停止监听并关闭服务器。
bool isListening() const  返回服务器是否正在监听连接。
QList<QTcpSocket*> pendingConnections()   返回等待处理的挂起连接的列表。
virtual void incomingConnection(qintptr socketDescriptor)     当有新连接时调用,可以在子类中实现以处理新连接。
void maxPendingConnections() const   返回允许的最大挂起连接数。
void setMaxPendingConnections(int numConnections)   设置允许的最大挂起连接数。
QNetworkProxy proxy() const   返回服务器的代理设置。
void setProxy(const QNetworkProxy &networkProxy)   设置服务器的代理设置。
QAbstractSocket::SocketError serverError() const     返回服务器的当前错误代码。
QString errorString() const    返回服务器的错误消息字符串。
void pauseAccepting()    暂停接受新连接,但保持现有连接。
void resumeAccepting()    恢复接受新连接。
void close()    关闭服务器。

如上这些只是常用函数的简要描述,详细的函数说明和用法可以参考Qt官方文档或相关文档。

1 通信的流程

1.1 服务端流程

在使用TCP通信时同样需要导入Qt+=network模块,并在头文件中引入QTcpServerQTcpSocket两个模块,当有了模块的支持,接着就是侦听套接字,此处可通过调用server.listen来实现侦听,此函数原型如下:

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

这个函数用于开始在指定的地址和端口上监听连接。它的参数包括:

  1.     address:一个QHostAddress对象,指定要监听的主机地址。默认为QHostAddress::Any,表示监听所有可用的网络接口。
  2.     port:一个quint16类型的端口号,指定要监听的端口。如果设置为0,系统将选择一个可用的未使用端口。

函数返回一个bool值,表示是否成功开始监听。如果成功返回true,否则返回false,并且可以通过调用errorString()获取错误消息。

紧随套接字侦听其后,通过使用一个waitForNewConnection等待新的连接到达。它的原型如下:

bool QTcpServer::waitForNewConnection(
    int msec = 0, 
    bool *timedOut = nullptr
);

该函数在服务器接受新连接之前会一直阻塞。参数包括:

  • msec:等待连接的超时时间(以毫秒为单位)。如果设置为0(默认值),则表示无限期等待,直到有新连接到达。
  • timedOut:一个可选的布尔指针,用于指示等待是否超时。如果传递了此参数,并且等待时间达到了指定的超时时间,*timedOut将被设置为true,否则为false。如果不关心超时,可以将此参数设置为nullptr。

函数返回一个布尔值,表示是否成功等待新连接。如果在超时时间内有新连接到达,返回true,否则返回false。如果等待超时,可以通过检查timedOut参数来确定。如果函数返回false,可以通过调用errorString()获取错误消息。

套接字的接收会使用nextPendingConnection()函数来实现,nextPendingConnection 是 QTcpServer 类的成员函数,用于获取下一个已接受的连接的套接字(QTcpSocket)。它的原型如下:

QTcpSocket *QTcpServer::nextPendingConnection();

函数返回一个指向新连接套接字的指针。如果没有已接受的连接,则返回 nullptr。

使用这个函数,你可以在服务器接受连接之后获取相应的套接字,以便进行数据传输和通信。一般来说,在收到 newConnection 信号后,你可以调用这个函数来获取新连接的套接字。

当有了套接字以后,就可以通过QTcpServer指针判断对应的套接字状态,一般套接字的状态被定义在QAbstractSocket类内。以下是QAbstractSocket类中定义的一些状态及其对应的标志:

状态标志描述
UnconnectedState未连接状态,套接字没有连接到远程主机。
HostLookupState正在查找主机地址状态,套接字正在解析主机名。
ConnectingState连接中状态,套接字正在尝试与远程主机建立连接。
ConnectedState已连接状态,套接字已经成功连接到远程主机。
BoundState已绑定状态,套接字已经与地址和端口绑定。
ClosingState关闭中状态,套接字正在关闭连接。
ListeningState监听中状态,用于QTcpServer,表示服务器正在监听连接。

这些状态反映了套接字在不同阶段的连接和通信状态。在实际使用中,可以通过调用state()函数获取当前套接字的状态,并根据需要处理相应的状态。例如,可以使用信号和槽机制来捕获状态变化,以便在连接建立或断开时执行相应的操作。

当套接字被连接后则可以通过socket->write()方法向上线客户端发送一个字符串,此处我们以发送lyshark例,发送时需要向write()中传入两个参数。其原型如下:

qint64 QTcpSocket::write(const char *data, qint64 maxSize);

该函数接受两个参数:

  • data:指向要写入套接字的数据的指针。
  • maxSize:要写入的数据的最大字节数。

函数返回实际写入的字节数,如果发生错误,则返回 -1。在写入数据之后,可以使用 bytesWritten 信号来获取写入的字节数。此外,你也可以使用 waitForBytesWritten 函数来阻塞等待直到所有数据都被写入。 

1.2 客户端流程

客户端的流程与服务端基本保持一致,唯一的区别在于将server.listen更换为socket.connectToHost连接到对应的主机,QTcpSocketconnectToHost 函数的原型如下:

void QTcpSocket::connectToHost(
const QString &hostName, 
quint16 port, 
OpenMode openMode = ReadWrite
);
  • hostName:远程主机的主机名或IP地址。
  • port:要连接的端口号。
  • openMode:套接字的打开模式,默认为 ReadWrite

函数用于初始化与指定远程主机和端口的连接。在实际使用中,你可以通过调用这个函数来发起与目标主机的连接尝试。

读取数据时可以使用readAll函数来实现,socket.readAll() 是 QTcpSocket 类的成员函数,用于读取所有可用的数据并返回一个 QByteArray 对象。其函数函数原型如下:

QByteArray QTcpSocket::readAll();

 该函数返回一个包含从套接字中读取的所有数据的 QByteArray 对象。通常,你可以通过这个函数来获取已经到达的所有数据,然后对这些数据进行进一步的处理。

2 图形化应用

2.1 服务端流程

        与命令行版本的网络通信不同,图形化部分需要使用信号与槽函数进行绑定,所有的通信流程都是基于信号的,对于服务端而言我们需要导入QTcpServerQtNetworkQTcpSocket模块,并新增四个槽函数分别对应四个信号;

信号      槽函数 描述
connected()  onClientConnected()    当 tcpSocket 成功连接到远程主机时触发,执行 onClientConnected() 函数。
disconnected()  onClientDisconnected()    当 tcpSocket 断开连接时触发,执行 onClientDisconnected() 函数。

stateChanged

(QAbstractSocket::SocketState)  

 onSocketStateChange

(QAbstractSocket::SocketState) 

   当 tcpSocket 的状态发生变化时触发,执行 onSocketStateChange() 函数,传递新的状态。
readyRead()    onSocketReadyRead()tcpSocket 有可读取的新数据时触发,执行 onSocketReadyRead() 函数。

在程序入口处我们通过new QTcpServer(this)新建TCP套接字类,并通过connect()连接到初始化槽函数上,当程序运行后会首先触发newConnection信号,执行newconect()槽函数。

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

    QString strip=GetLocalIpAddress();
    //QMessageBox::information(this,"数据",strip,QMessageBox::Yes);

    ui->comboBox_ip->addItem(strip);

    tcpserver=new QTcpServer(this);
    connect(tcpserver,SIGNAL(newConnection()),this,SLOT(newconect()));

}

而在槽函数newconect()中,通过nextPendingConnection新建一个套接字,并绑定其他四个槽函数,这里的槽函数功能各不相同,将其对应的信号绑定到对应槽函数上即可;

void MainWindow::newconect()
{
    // 创建新套接字
    tcpsocked=tcpserver->nextPendingConnection();
    // 连接触发信号
    connect(tcpsocked,SIGNAL(connected()),this,SLOT(clientconnect()));
    clientconnect();
    // 关闭触发信号
    connect(tcpsocked,SIGNAL(disconnected()),this,SLOT(clientdisconnect()));
    // 状态改变触发信号
    connect(tcpsocked,SIGNAL(stateChanged(QAbstraSocket::SocketState)),this,
            SLOT(OnSocketStateChanged(tcpsocked->state())));
    // 读入数据触发信号
    connect(tcpsocked,SIGNAL(readyRead()),this,SLOT(socketreaddata()));
}

当读者点击侦听时则直接调用tcpserver->listen实现对本地IP的函数实现,如下所示;端口的侦听功能,停止侦听则是调用tcpServer->close


void MainWindow::on_pushButton_Start_clicked()
{
    QString ip=ui->comboBox_ip->currentText();
    quint16 port=ui->spinBox_port->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();
        ui->pushButton_Start->setEnabled(true);
        ui->pushButton_Stop->setEnabled(false);
    }
}

对于读取数据可以通过canReadLine()函数判断行,并通过tcpClient->readLine()逐行读入数据,相对应的发送数据可通过调用tcpsocket->write函数实现,在发送之前需要将其转换为QByteArray类型的字符串格式,如下所示;

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

void MainWindow::on_pushButton_InputMesg_clicked()
{
    QString strmsg=ui->lineEdit->text();
    ui->plainTextEdit_DispMsg->appendPlainText("[out]:"+strmsg);

    ui->lineEdit->clear();

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

2.2 客户端流程

对于客户端而言同样需要绑定四个信号并对应到特定的槽函数上,其初始化部分与服务端保持一致,唯一不同的是客户端使用connectToHost函数链接到服务端上,断开连接时使用的是disconnectFromHost函数,如下所示;

void MainWindow::on_pushButton_connect_clicked()
{
    QString addr=ui->comboBox->currentText();
    quint16 port=ui->spinBox->value();
    tcpclient->connectToHost(addr,port);
}

void MainWindow::on_pushButton_disconnect_clicked()
{
    if(tcpclient->state()==QAbstractSocket::ConnectedState){
        tcpclient->disconnectFromHost();
    }
}

此处的读取数据与服务端保持一致,发送数据时则是通过tcpClient->write(str)函数直接传递给客户端,代码如下所示;

void MainWindow::socketreaddata()
{
    qDebug()<<"hahahah";
    while(tcpclient->canReadLine()){
        ui->plainTextEdit->appendPlainText("[in]:"+tcpclient->readLine());
    }
}


void MainWindow::on_pushButton_send_clicked()
{
    QString strmsg=ui->lineEdit->text();
    ui->plainTextEdit->appendPlainText("[out]:"+strmsg);
    ui->lineEdit->clear();
    QByteArray str=strmsg.toUtf8();
    str.append('\n');

    tcpclient->write(str);
}

运行后,服务端启用侦听等待客户端连接,客户端连接后,双方则可以实现数据的收发功能,由于采用了信号机制,两者的收发并不会阻断可同时进行,如下图所示;

具体ui文件布局和头文件没有放出来,就是定义一些量和函数等

完整代码:客户端:

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

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

    QString strip=getlocalip();

    ui->comboBox->addItem(strip);

    connect(tcpclient,SIGNAL(connected()),this,SLOT(connectfunc()));
    connect(tcpclient,SIGNAL(disconnected()),this,SLOT(disconnectfunc()));
    connect(tcpclient,SIGNAL(stateChanged(QAbstraSocket::SocketState)),this,
            SLOT(OnSocketStateChanged(tcpclient->state())));
    connect(tcpclient,SIGNAL(readyRead()),this,SLOT(socketreaddata()));

}

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

QString MainWindow::getlocalip()
{
    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;
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if(tcpclient->state()==QAbstractSocket::ConnectedState){
        tcpclient->disconnectFromHost();
    }
    event->accept();
}

void MainWindow::connectfunc()
{
    ui->plainTextEdit->appendPlainText("********连接到服务器端********");
    ui->plainTextEdit->appendPlainText("********peer address:"+tcpclient->peerAddress().toString());
    ui->plainTextEdit->appendPlainText("********peer port:"+QString::number(tcpclient->peerPort()));

    ui->pushButton_connect->setEnabled(false);
    ui->pushButton_disconnect->setEnabled(true);
}

void MainWindow::disconnectfunc()
{
    ui->plainTextEdit->appendPlainText("********已断开与服务器之间连接********");

    ui->pushButton_connect->setEnabled(true);
    ui->pushButton_disconnect->setEnabled(false);
}

void MainWindow::socketreaddata()
{
    qDebug()<<"hahahah";
    while(tcpclient->canReadLine()){
        ui->plainTextEdit->appendPlainText("[in]:"+tcpclient->readLine());
    }
}

void MainWindow::on_pushButton_connect_clicked()
{
    QString addr=ui->comboBox->currentText();
    quint16 port=ui->spinBox->value();
    tcpclient->connectToHost(addr,port);
}

void MainWindow::on_pushButton_disconnect_clicked()
{
    if(tcpclient->state()==QAbstractSocket::ConnectedState){
        tcpclient->disconnectFromHost();
    }
}

void MainWindow::on_pushButton_send_clicked()
{
    QString strmsg=ui->lineEdit->text();
    ui->plainTextEdit->appendPlainText("[out]:"+strmsg);
    ui->lineEdit->clear();
    QByteArray str=strmsg.toUtf8();
    str.append('\n');

    tcpclient->write(str);
}

服务器端:

#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();
    //QMessageBox::information(this,"数据",strip,QMessageBox::Yes);

    ui->comboBox_ip->addItem(strip);

    tcpserver=new QTcpServer(this);
    connect(tcpserver,SIGNAL(newConnection()),this,SLOT(newconect()));

}

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

QString MainWindow::GetLocalIpAddress()
{
    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:"+tcpsocked->peerAddress().toString());
    ui->plainTextEdit_DispMsg->appendPlainText("***********peer port:"+QString::number(tcpsocked->peerPort()));

}

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

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

void MainWindow::newconect()
{
    tcpsocked=tcpserver->nextPendingConnection();

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

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

    connect(tcpsocked,SIGNAL(stateChanged(QAbstraSocket::SocketState)),this,
            SLOT(OnSocketStateChanged(tcpsocked->state())));

    connect(tcpsocked,SIGNAL(readyRead()),this,SLOT(socketreaddata()));
}


void MainWindow::on_pushButton_Start_clicked()
{
    QString ip=ui->comboBox_ip->currentText();
    quint16 port=ui->spinBox_port->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();
        ui->pushButton_Start->setEnabled(true);
        ui->pushButton_Stop->setEnabled(false);
    }
}

void MainWindow::on_pushButton_InputMesg_clicked()
{
    QString strmsg=ui->lineEdit->text();
    ui->plainTextEdit_DispMsg->appendPlainText("[out]:"+strmsg);

    ui->lineEdit->clear();

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

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

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

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

相关文章

状态分解定义互斥和并行模式练习

互斥 (OR) 状态分解 带有实线边框的子状态表示互斥 (OR) 状态分解。此分解可用于描述互斥工作模式。当状态拥有互斥 (OR) 分解时&#xff0c;一次只能有一个子状态激活。 并行 (AND) 状态分解 带有虚线边框的子状态表示并行 (AND) 状态分解。使用此分解可以描述并行工作模式…

程序员自由创业周记#33:创业者的一天

程序员自由创业周记#33&#xff1a;创业者的一天 一天的安排 只工作不上班的日子是非常考验一个人自律能力的&#xff0c;如果顶不住各种诱惑&#xff0c;一天的时间转瞬即逝。尤其对我这种兴趣极其广泛的人。如果不自律&#xff0c;上午一场NBA比赛就过去了&#xff1b;如果不…

西奥机电CLRT-01:重塑碳酸饮料质检新纪元

西奥机电CLRT-01&#xff1a;重塑碳酸饮料质检新纪元 在追求品质生活的今天&#xff0c;碳酸饮料的品质检测成为了行业内外关注的焦点。西奥机电&#xff0c;作为行业创新的领跑者&#xff0c;携其最新研发的CLRT-01二氧化碳气容量测试仪&#xff0c;为碳酸饮料行业带来了革命性…

Python 散点图分类别标签+不同颜色区分

文章目录 1. 前言2. 实现2.1 构建数据对2.2 构建colors_map2.3 绘制图 3. 完整示例 1. 前言 在散点图中&#xff0c;我们有时候希望把不同类别的点用不同颜色区分&#xff0c;并且不同类别有图例标签标明&#xff0c;实现类似如下的结果&#xff1a; 2. 实现 2.1 构建数据对…

可重入分布式锁有哪些应用场景

原文连接&#xff1a;可重入分布式锁有哪些应用场景 https://mp.weixin.qq.com/s/MTPS9V8jn5J91wr-UD4DyA 之前发过的一篇实现Redis分布式锁的8大坑中&#xff0c;有粉丝留言说&#xff0c;分布式锁的可重入特性在工作中有哪些应用场景&#xff0c;那么我们这篇文章就来看一下…

pythonsql-随机问答小程序

随机问答-python&sql 智力问答测试&#xff0c;在答题过程中对做对、做错进行实时跟踪&#xff0c;测试完成后能根据玩家的答题情况给出成绩。 1. 设计思路 程序使用了一个SQLite试题库test.db&#xff0c;其中每个智力问答山题目、4个选项*1-1正确答案组成(question, An…

Spring boot环境的常见问题

文章目录 一、启动类无法运行二、包相关问题2.1 默认配置的包无法下载2.2 第三方库的包无法下载2.3 包找不到 三、出现了一个无效的源发行版17四、类文件具有错误的版本 61.0&#xff0c;应为52.0五、控制台乱码 一、启动类无法运行 原因&#xff1a;IDEA 没有把当前项目识别成…

macos安装mysql一直卡在安装成功那个页面选项的解决办法

问题描述&#xff1a; 我安装的是比较新的版本8.0.37&#xff0c;安装过程中一直卡在安装那个选项上&#xff0c;且页面提示安装成功了&#xff0c;但就是死活不往下面的配置选项那一步走。 解决办法&#xff1a; 1.首先清理掉之前的mysql sudo rm -rf /usr/local/mysql2.然…

MATLAB模拟退火算法、遗传算法、蚁群算法、粒子群算法

概况 模拟退火算法、遗传算法、蚁群算法、粒子群算法等算法&#xff0c;都是属于概率算法&#xff0c;不绝对&#xff0c;不迅速&#xff0c;能用其它方式解决的问题&#xff0c;不要用这些相对复杂的算法&#xff0c;比如有明确的线性关系或者非线性对应关系。这里的概率算法…

二氧化碳在饮料汽水中的作用与西奥机电CLRT-01二氧化碳气容量测试仪的重要性

二氧化碳在饮料汽水中的作用与西奥机电CLRT-01二氧化碳气容量测试仪的重要性 一、引言 当我们打开一瓶冰镇的汽水&#xff0c;那独特的口感和清凉感总是让人心旷神怡。而这一切&#xff0c;都离不开其中溶解的二氧化碳。本文将详细解析二氧化碳在饮料汽水中的作用&#xff0c…

Jenkins docker 自动化部署python3后端 centos8.5 运维系列四

1安装expect yum install expect 2 jenkins 新建任务 #cat qysup.sh #!/usr/bin/expect -f set port 22 set user root set host ip set password 密码 set timeout 60 spawn ssh $user$host expect "password:" send "$password\r" expect "]#&qu…

Golang | Leetcode Golang题解之第73题矩阵置零

题目&#xff1a; 题解&#xff1a; func setZeroes(matrix [][]int) {n, m : len(matrix), len(matrix[0])col0 : falsefor _, r : range matrix {if r[0] 0 {col0 true}for j : 1; j < m; j {if r[j] 0 {r[0] 0matrix[0][j] 0}}}for i : n - 1; i > 0; i-- {for …

面试笔记——JVM组成

基本介绍 JVM: Java Virtual Machine Java程序的运行环境&#xff08;java二进制字节码的运行环境&#xff09; 使用JVM的好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收机制 JVM的组成及运行流程&#xff1a; 程序计数器 程序计数器&a…

用Rust打印杨辉三角

一、杨辉三角是什么&#xff1f; 杨辉三角是一个著名的数学图形&#xff0c;它展示了二项式系数的排列方式。 杨辉三角是一种将二项式系数以三角形阵列排列的数学图形&#xff0c;具有丰富的历史和数学意义。 杨辉三角的历史起源可以追溯到中国南宋时期&#xff0c;由数学家杨辉…

同创优配正规炒股A股三大指数集体收涨 创指重回1900点关口

查查配5月9日电 周四,A股三大指数震荡上扬。截至收盘,上证指数涨0.83%,报3154.32点;深证成指涨1.55%,报9788.07点;创业板指涨1.87%,报1900.01点。总体上个股涨多跌少,全市场超4200只个股上涨。沪深两市今日成交额9011亿元,较上个交易日放量367亿元。 同创优配是AAA 级诚信经营…

内存卡不小心格式化了怎么办?3个方法解决数据丢失问题!

“很奇怪&#xff0c;我的内存卡不小心中病毒了&#xff0c;刚刚在清理病毒时不小心把内存卡格式化了。我保存了很多重要的数据在里面&#xff0c;还有方法可以恢复这些数据吗&#xff1f;” 在数字设备日益普及的今天&#xff0c;内存卡已成为我们存储和传输数据的重要工具。但…

竖排文字识别原理与实践操作方法

在当今数字化时代&#xff0c;OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;技术已经广泛应用于各个领域&#xff0c;特别是在文档处理方面&#xff0c;OCR软件能够帮助用户快速将纸质文档转化为可编辑的电子文档。然而&#xff0c;对于竖…

OpenSearch 与 Elasticsearch:7 个主要差异及如何选择

OpenSearch 与 Elasticsearch&#xff1a;7 个主要差异及如何选择 1. 什么是 Elasticsearch&#xff1f; Elasticsearch 是一个基于 Apache Lucene 构建的开源、RESTful、分布式搜索和分析引擎。它旨在处理大量数据&#xff0c;使其成为日志和事件数据管理的流行选择。 Elasti…

顺序表的实现(迈入数据结构的大门)(2)

目录 顺序表的头插(SLPushFront) 此时&#xff1a;我们有两个思路&#xff08;数组移位&#xff09; 顺序表的头删(学会思维的变换)(SLPopFront) 顺序表的尾插(SLPushBack) 有尾插就有尾删 既然头与尾部的插入与删除都有&#xff0c;那必然少不了指定位置的插入删除 查找…

Python嵌套绘图并为条形图添加自定义标注

论文绘图时经常需要多图嵌套&#xff0c;正好最近绘图用到了&#xff0c;记录一下使用Python实现多图嵌套的过程。 首先&#xff0c;实现 Seaborn 分别绘制折线图和柱状图。 绘制折线图import seaborn as snsimport matplotlib.pyplot as pltimport warningswarnings.filterw…