当前位置: 首页 > news >正文

Qt 网络通信

获取本机网络信息

(1)在 .pro 文件中加入

QT       += network

(2)

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QDebug>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QMessageBox>
#include <QGridLayout>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void getHostInfo();private slots:void slot_Detail();private:QLabel *HostLabel;QLineEdit *HostNameLineEdit;QLabel *IpLabel;QLineEdit *AddressLineEdit;QPushButton *DetailBtn;QGridLayout *mainLay;
};
#endif // WIDGET_H

(3)

#include "widget.h"
#include <QNetworkInterface>
#include <QHostInfo>
#include <QString>
#include <QHostAddress>
#include <QNetworkAddressEntry>Widget::Widget(QWidget *parent): QWidget(parent)
{this->resize(400, 300);HostLabel = new QLabel("主机名: ");HostNameLineEdit = new QLineEdit;IpLabel = new QLabel("IP 地址: ");AddressLineEdit = new QLineEdit;DetailBtn = new QPushButton("详细");mainLay = new QGridLayout(this);mainLay->addWidget(HostLabel, 0, 0, 1, 1);mainLay->addWidget(IpLabel, 1, 0, 1, 1);mainLay->addWidget(HostNameLineEdit, 0, 1, 1, 2);mainLay->addWidget(AddressLineEdit, 1, 1, 1, 2);mainLay->addWidget(DetailBtn, 2, 0, 1, 3);getHostInfo();connect(DetailBtn, &QPushButton::clicked, this, &Widget::slot_Detail);
}Widget::~Widget()
{
}void Widget::getHostInfo()
{// 获取本机主机名,QHostInfo 提供了一系列有关网络信息的静态函数// 即可以根据主机名获取分配的 IP 地址,也可以根据 IP 地址获取相应的主机名。QString localHostName = QHostInfo::localHostName();HostNameLineEdit->setText(localHostName);// 根据主机名获取相关主机信息,包括 IP 地址等// fromName() 函数通过主机名查找 IP 地址信息QHostInfo hostInfo = QHostInfo::fromName(localHostName);//  获取主机 Ip 地址列表QList<QHostAddress> listAddress = hostInfo.addresses();if(!listAddress.isEmpty()) {AddressLineEdit->setText(listAddress.at(2).toString());}
}void Widget::slot_Detail()
{QString detail = "";// 获取主机IP地址和网络接口列表QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();for(int i = 0; i < list.count(); ++i) {QNetworkInterface interface = list.at(i);// 获取网络接口的名称detail = detail + "设备: " + interface.name() + "\n";// 获取网络接口的硬件地址detail = detail + "硬件地址: " + interface.hardwareAddress() + "\n";// 每个网络借口包括0个或多个IP地址,每个IP地址有选择性地与一个子网掩码或一个广播地址相关联// QNetworkAddressEntry类,存储了被网络接口支持的一个IP地址,同时还包括与之相关的子网掩码和广播地址QList<QNetworkAddressEntry> entryList = interface.addressEntries();for(int j = 1; j < entryList.count(); ++j) {QNetworkAddressEntry entry = entryList.at(j);detail = detail + "\t" + "IP 地址: " + entry.ip().toString() + "\n";detail = detail + "\t" + "子网掩码: " + entry.netmask().toString() + "\n";detail = detail + "\t" + "广播地址: " + entry.broadcast().toString() + "\n";}}QMessageBox::information(this, "Detail", detail);
}

基千 UDP 的网络广播程序

在这里插入图片描述
服务端定时发送数据,客户端接收

Client:

(1)

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTextEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QDialog>
#include <QUdpSocket>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();public slots:void CloseBtnClicked();void dataReceived();private:QTextEdit *ReceiveTextEdit;QPushButton *CloseBtn;QVBoxLayout *mainLay;int port;QUdpSocket *UdpSocket;
};
#endif // WIDGET_H

(2)

#include "widget.h"
#include <QMessageBox>
#include <QHostAddress>
#include <QByteArray>Widget::Widget(QWidget *parent): QWidget(parent)
{this->setWindowTitle("UDP Client");this->resize(300, 300);ReceiveTextEdit = new QTextEdit(this);CloseBtn = new QPushButton("Close", this);mainLay = new QVBoxLayout(this);mainLay->addWidget(ReceiveTextEdit);mainLay->addWidget(CloseBtn);connect(CloseBtn, &QPushButton::clicked, this, &Widget::CloseBtnClicked);port = 5555;UdpSocket = new QUdpSocket(this);// 当有数据到达I/O设备时(在这里是UdpSocket),发出 readyRead() 信号connect(UdpSocket, &QUdpSocket::readyRead, this, &Widget::dataReceived);// 被动接收数据的一方必须绑定固定端口,UDP通信中并无严格的服务端与客户端的区别bool res = UdpSocket->bind(port); // 绑定到指定端口上if(!res) {QMessageBox::information(this, "error", "udp socket create error");return;}}Widget::~Widget()
{
}void Widget::CloseBtnClicked()
{close();
}void Widget::dataReceived()
{// 将数据读出并显示// 判断 UdpSocket 中是否有数据报可读// hasPendingDatagrams() 在至少有一个数据报可读时返回 truewhile(UdpSocket->hasPendingDatagrams()) {QByteArray datagram;// pendingDatagramSize()  Returns the size of the first pending UDP datagram.// If there is no datagram available, this function returns -1.datagram.resize(UdpSocket->pendingDatagramSize());// qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr)// Receives a datagram and stores it in data// datagram.data() : char * QByteArray::data()UdpSocket->readDatagram(datagram.data(), datagram.size());QString msg = datagram.data();ReceiveTextEdit->insertPlainText(msg);}
}

Server

(1)

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QUdpSocket>
#include <QTimer>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();public slots:void StartBtnClicked();void Timeout();
private:QLabel *TimerLabel;QLineEdit *TextLineEdit;QPushButton *StartBtn;QVBoxLayout *mainLay;int port;bool isStarted;QUdpSocket *UdpSocket;QTimer *Timer;
};
#endif // WIDGET_H

(2)

#include "widget.h"
#include <QHostAddress>
#include <QString>
#include <QMessageBox>Widget::Widget(QWidget *parent): QWidget(parent)
{setWindowTitle("UDP Server");this->resize(300, 100);TimerLabel = new QLabel("计时器", this);TextLineEdit = new QLineEdit(this); // 要传输的文本StartBtn = new QPushButton("开始", this);mainLay = new QVBoxLayout(this);mainLay->addWidget(TimerLabel);mainLay->addWidget(TextLineEdit);mainLay->addWidget(StartBtn);isStarted = false;Timer = new QTimer(this);// 按钮控制定时器开关connect(StartBtn, &QPushButton::clicked, this, &Widget::StartBtnClicked);port = 5555;UdpSocket = new QUdpSocket(this);//  定时发送广播信息connect(Timer, &QTimer::timeout, this, &Widget::Timeout);
}Widget::~Widget()
{
}void Widget::StartBtnClicked()
{if(!isStarted) {// 上一个状态没有被启动,那么点击之后应该启动StartBtn->setText("停止");Timer->start(1000);isStarted = true;}else {// 上一个状态没有被启动,那么点击之后应该停止StartBtn->setText("开始");isStarted = false;Timer->stop();}
}void Widget::Timeout()// 定时向端口发送广播信息
{QString msg = TextLineEdit->text(); // 读取要传输的文本if(msg.isEmpty()) return;// qint64 writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port)// Sends the datagram// QByteArray QString::toLatin1() const// QHostAddress::Broadcast ,指定向广播地址发送,The IPv4 broadcast address. Equivalent to QHostAddress("255.255.255.255").int len = UdpSocket->writeDatagram(msg.toLatin1().data(), msg.length(), QHostAddress::Broadcast, port);if(len != msg.length()){// 返回 -1,没有传输成功QMessageBox::information(this, "error", "传输失败");}
}

基千 TCP 的网络聊天室程序

QTcpServer 类

QTcpServer 类用于监听客户端连接以及和客户端建立连接

函数

构造函数:

QTcpServer::QTcpServer(QObject *parent = Q_NULLPTR);

设置监听:

// port:如果指定为0表示随机绑定一个可用端口。
bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);// 判断当前对象是否在监听, 是返回true,没有监听返回false
bool QTcpServer::isListening() const;// 如果当前对象正在监听,则返回监听的服务器地址信息, 否则返回 QHostAddress::Null
QHostAddress QTcpServer::serverAddress() const;// 如果服务器正在侦听连接,则返回服务器的端口; 否则返回0
quint16 QTcpServer::serverPort() const

处理来自客户端的请求

// 当一个来自客户端建立连接的新请求可以处理时,自动调用该函数
[virtual protected] void QTcpServer::incomingConnection(qintptr socketDescriptor)
// 需要把新建的通信套接字的描述符设为参数 socketDescriptor

信号

// 当接受新连接导致错误时,将发射如下信号。socketError参数描述了发生的错误相关的信息。
[signal] void QTcpServer::acceptError(QAbstractSocket::SocketError socketError);// 每次有新连接可用时都会发出 newConnection() 信号。
[signal] void QTcpServer::newConnection();

QTcpSocket 类

QTcpSocket是一个套接字通信类,不管是客户端还是服务器端都需要使用。在Qt中发送和接收数据也属于IO操作(网络IO)

函数

构造函数:

QTcpSocket::QTcpSocket(QObject *parent = Q_NULLPTR);

连接服务器:

[virtual] void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);[virtual] void QAbstractSocket::connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode = ReadWrite);

I / O 操作:

// 指定可接收的最大字节数 maxSize 的数据到指针 data 指向的内存中
qint64 QIODevice::read(char *data, qint64 maxSize);
// 指定可接收的最大字节数 maxSize,返回接收的字符串
QByteArray QIODevice::read(qint64 maxSize);
// 将当前可用操作数据全部读出,通过返回值返回读出的字符串
QByteArray QIODevice::readAll();// 发送指针 data 指向的内存中的 maxSize 个字节的数据
qint64 QIODevice::write(const char *data, qint64 maxSize);
// 发送指针 data 指向的内存中的数据,字符串以 \0 作为结束标记
qint64 QIODevice::write(const char *data);
// 发送参数指定的字符串
qint64 QIODevice::write(const QByteArray &byteArray);

信号

// 在使用QTcpSocket进行套接字通信的过程中,如果该类对象发射出readyRead()信号,说明对端发送的数据达到了
// 之后就可以调用 read 函数接收数据了。
[signal] void QIODevice::readyRead();// 调用connectToHost()函数并成功建立连接之后发出connected()信号。
[signal] void QAbstractSocket::connected();// 在套接字断开连接时发出disconnected()信号。
[signal] void QAbstractSocket::disconnected();

局域网聊天(客户端)

要保证客户端能连接服务器端,在同一 wifi 下聊天可以自行百度修改防火墙配置,或者租个服务器运行客户端(也要设置防火墙允许Tcp连接)

新建一个名为 TcpClient 的类,这里我继承自 QWidget
(1)tcpclient.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QListWidget>
#include <QPushButton>
#include <QLabel>
#include <QGridLayout>
#include <QLineEdit>#include <QHostAddress>
#include <QString>
#include <QTcpSocket>class TcpClient : public QWidget
{Q_OBJECTpublic:TcpClient(QWidget *parent = nullptr);~TcpClient();private:QListWidget *contentListWidget;QLineEdit *sendLineEdit;QPushButton *sendBtn;QLabel *userNameLabel;QLineEdit *userNameLineEdit;QLabel *serverIPLabel;QLineEdit *serverIPLineEdit;QLabel *portLabel;QLineEdit *portLineEdit;QPushButton *enterBtn;QGridLayout *mainLay;bool status; // true 表示已经进入聊天室,false表示已经离开聊天室int port;QHostAddress *serverIP;QString userName;QTcpSocket *tcpSocket;public slots:void slot_Enter();void slot_Connected();void slot_Disconnected();void slot_DataReceived();void slot_Send();
};
#endif // WIDGET_H

(2)tcpclient.cpp 里实现

#include "tcpclient.h"#include <QMessageBox>
#include <QHostInfo>TcpClient::TcpClient(QWidget *parent): QWidget(parent)
{setWindowTitle("TCP Client");contentListWidget = new QListWidget;sendLineEdit = new QLineEdit;sendBtn = new QPushButton("发送");userNameLabel = new QLabel("用户名: ");userNameLineEdit = new QLineEdit;serverIPLabel = new QLabel("服务器地址: ");serverIPLineEdit = new QLineEdit;portLabel = new QLabel("端口: ");portLineEdit = new QLineEdit;enterBtn = new QPushButton("进入聊天室");mainLay = new QGridLayout(this);mainLay->addWidget(contentListWidget, 0, 0, 1, 2);mainLay->addWidget(sendLineEdit, 1, 0, 1, 1);mainLay->addWidget(sendBtn, 1, 1, 1, 1);mainLay->addWidget(userNameLabel, 2, 0, 1, 1);mainLay->addWidget(userNameLineEdit, 2, 1, 1, 1);mainLay->addWidget(serverIPLabel, 3, 0, 1, 1);mainLay->addWidget(serverIPLineEdit, 3, 1, 1, 1);mainLay->addWidget(portLabel, 4, 0, 1, 1);mainLay->addWidget(portLineEdit, 4, 1, 1, 1);mainLay->addWidget(enterBtn, 5, 0, 1, 2);status = false;port = 8010;portLineEdit->setText(QString::number(port));serverIP = new QHostAddress();serverIPLineEdit->setText("127.0.0.1");// 服务器的ip地址connect(enterBtn, &QPushButton::clicked, this, &TcpClient::slot_Enter);connect(sendBtn, &QPushButton::clicked, this, &TcpClient::slot_Send);// 设置按钮不能处理键盘和鼠标事件sendBtn->setEnabled(false);
}TcpClient::~TcpClient()
{
}void TcpClient::slot_Enter()
{ // 实现进入和离开聊天室的功能if(!status) {QString ip = serverIPLineEdit->text();// 判断给定的IP地址能否被正确解析// setAddress参数为QString时,调用的是有bool返回值的重载函数if(!serverIP->setAddress(ip)) {QMessageBox::information(this, "error", "server ip address error");return;}if(userNameLineEdit->text().isEmpty()) {QMessageBox::information(this, "error", "User name can't be empty");return;}userName = userNameLineEdit->text();tcpSocket = new QTcpSocket(this);connect(tcpSocket, &QTcpSocket::connected, this, &TcpClient::slot_Connected);connect(tcpSocket, &QTcpSocket::disconnected, this, &TcpClient::slot_Disconnected);connect(tcpSocket, &QTcpSocket::readyRead, this, &TcpClient::slot_DataReceived);// 与TCP服务器连接,连接成功后发出 connected 信号tcpSocket->connectToHost(*serverIP, port);status = true;}else {QString msg = userName + " : Leave Chat Room";int len = tcpSocket->write(msg.toUtf8(), msg.length());if(len != msg.length()) return;// 断开连接,之后发出 disconnected 信号tcpSocket->disconnectFromHost();status = false;}
}void TcpClient::slot_Connected()
{sendBtn->setEnabled(true);enterBtn->setText("离开");QString msg = userName + " Enter Chat Room";int len = tcpSocket->write(msg.toUtf8(), msg.length());if(len != msg.length()) {QMessageBox::information(this, "error", "enter chat room failed");return;}
}void TcpClient::slot_Disconnected()
{sendBtn->setEnabled(false);enterBtn->setText("进入聊天室");
}void TcpClient::slot_DataReceived()
{while(tcpSocket->bytesAvailable() > 0) {
//        QByteArray datagram;
//        datagram.resize(tcpSocket->bytesAvailable());
//        tcpSocket->read(datagram.data(), datagram.size());
//        QString msg = datagram.data();
//        msg = msg.left(datagram.size());QString msg = QString::fromUtf8(tcpSocket->readAll());contentListWidget->addItem(msg);}
}void TcpClient::slot_Send()
{if(sendLineEdit->text().isEmpty()) return;QString msg = userName + ":" + sendLineEdit->text();
//    qDebug() << "Client send : " << msg << " size = " << msg.size() << " length : " << msg.length();tcpSocket->write(msg.toUtf8(), msg.toUtf8().size());sendLineEdit->clear();
}

局域网聊天(服务器端)

新建一个 TcpServer 类,这里我也继承自了 QWidget

做界面设计
直接用封装的 QTcpServer 即可

(1)tcpserver.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QGridLayout>
#include <QListWidget>#include "server.h"class TcpServer : public QWidget
{Q_OBJECTpublic:TcpServer(QWidget *parent = nullptr);~TcpServer();private:QListWidget *ContentListWidget;QLabel *PortLabel;QLineEdit *PortLineEdit;QPushButton *CreateBtn;QGridLayout *mainLay;int port;Server *server;public slots:void slot_CreateServer();void slot_updateServer(QString, int);
};
#endif // WIDGET_H

(2)tcpserver.cpp

#include "tcpserver.h"TcpServer::TcpServer(QWidget *parent): QWidget(parent)
{setWindowTitle("TCP Server");this->resize(300, 300);ContentListWidget = new QListWidget;PortLabel = new QLabel("端口: ");PortLineEdit = new QLineEdit;CreateBtn = new QPushButton("创建聊天室");mainLay = new QGridLayout(this);mainLay->addWidget(ContentListWidget, 0, 0, 2, 2);mainLay->addWidget(PortLabel, 2, 0, 1, 1);mainLay->addWidget(PortLineEdit, 2, 1, 1, 1);mainLay->addWidget(CreateBtn, 3, 0, 1, 2);port = 8010;PortLineEdit->setText(QString::number(port));connect(CreateBtn, &QPushButton::clicked, this, &TcpServer::slot_CreateServer);}TcpServer::~TcpServer()
{}void TcpServer::slot_CreateServer()
{server = new Server(this, port);connect(server, &Server::signal_updateServer, this, &TcpServer::slot_updateServer);// QPushButtn 继承自 QWidget// In general an enabled widget handles keyboard and mouse events; a disabled widget does not.CreateBtn->setEnabled(false);
}void TcpServer::slot_updateServer(QString msg, int len)
{ContentListWidget->addItem(msg.left(len));
}

自定义TcpClientSocket 类,继承自 QTcpSocket

服务器端用来和客户端通信的套接字,这里要进行自定义的一个原因是:服务器端通信套接字,接收完消息要进行一个转发,类似于回声服务器,但是这里不仅要发给发送消息的客户端,还要发送给其他客户端。我们需要在读完数据后立马触发信号,这样就能即时更新消息。

(1)tcpclientsocket.h

#ifndef TCPCLIENTSOCKET_H
#define TCPCLIENTSOCKET_H#include <QTcpSocket>
#include <QObject>class TcpClientSocket : public QTcpSocket
{Q_OBJECT
public:TcpClientSocket(QObject *parent = 0);
// 服务端用于通信的套接字
signals:void signal_updateClients(QString, int); // 通知服务器向聊天室内的所有成员广播信息void signal_Disconnected(int);protected slots:void slot_DataReceived();void slot_Disconnected();
};#endif // TCPCLIENTSOCKET_H

(2)tcpclientsocket.cpp

#include "tcpclientsocket.h"
// 服务器端通信的套接字
TcpClientSocket::TcpClientSocket(QObject *)
{
//    if(parent) this->setParent(parent);// once every time new data is available for reading from the device's current read channel.connect(this, &QTcpSocket::readyRead, this, &TcpClientSocket::slot_DataReceived);// when the socket has been disconnected.connect(this, &QTcpSocket::disconnected, this, &TcpClientSocket::slot_Disconnected);}void TcpClientSocket::slot_DataReceived()
{// 读出数据//  qint64 QAbstractSocket::bytesAvailable() const// Returns the number of incoming bytes that are waiting to be read.while(this->bytesAvailable() > 0) {QString msg = QString::fromUtf8(this->readAll());int len = msg.size();//qDebug() << "server receive :" << msg;// 服务器端接收来自客户端的数据结束,向聊天室内的所有成员广播信息emit signal_updateClients(msg, len); }
}void TcpClientSocket::slot_Disconnected()
{// socketDescriptor() 用于获取底层的套接字描述符, 通常是一个整数// 向监听QTcpServer发送当前断开连接的套接字的描述符(套接字编号)emit signal_Disconnected(this->socketDescriptor());
}

自定义 Server 类,继承自 QTcpServer

QTcpServer 的作用就是监听来自客户端的请求

(1)server.h

#ifndef SERVER_H
#define SERVER_H#include <QTcpServer>
#include <QObject>
#include <QList>
#include "tcpclientsocket.h"class Server : public QTcpServer
{Q_OBJECTpublic:Server(QObject *parent = 0, int port = 0);// 保存与客户端连接的 TcpClientSocketQList<TcpClientSocket *> tcpClientSocketList;signals:void signal_updateServer(QString, int);// 更新ui,聊天室内容public slots:void slot_updateClients(QString, int);void slot_Disconnected(int);protected: // 重载函数别写错了,32位写int,64位写long longvoid incomingConnection(long long socketDescriptor);
};#endif // SERVER_H

(2)server.cpp

#include "server.h"
#include <QHostAddress>Server::Server(QObject *parent, int port) : QTcpServer(parent)
{// 在指定的port端口,对任意地址进行监听listen(QHostAddress::Any, port);
}
// 类似于accept,但此函数自动调用,处理来自客户端建立链接的请求
void Server::incomingConnection(long long socketDescriptor)
{// 新建一个用于和客户端通信的 TcpSocketTcpClientSocket *tcpClientSocket = new TcpClientSocket(this);// 如果tcpClientSocket接受完来自客户端的信息,触发更新connect(tcpClientSocket, &TcpClientSocket::signal_updateClients, this, &Server::slot_updateClients);// 监听用于通信的套接字是否断开连接connect(tcpClientSocket, &TcpClientSocket::signal_Disconnected, this, &Server::slot_Disconnected);//将新创建的通信套接字的描述符指定为参数socketdescriptortcpClientSocket->setSocketDescriptor(socketDescriptor);//将这个套接字加入客户端套接字列表中tcpClientSocketList.append(tcpClientSocket);
}void Server::slot_updateClients(QString msg, int len)
{// 服务器端将刚刚接收自某个客户端的信息,发送到所有客户端,实现聊天室消息同步// 更新服务器对话框的内容emit signal_updateServer(msg, len);// 向聊天室内的所有成员广播信息for(int i = 0; i < tcpClientSocketList.count(); ++i) {// 取出与第i个客户端建立连接的用于通信的套接字QTcpSocket *tmp = tcpClientSocketList.at(i);if(tmp->write(msg.toUtf8(), msg.toUtf8().size()) != msg.toUtf8().size()) {continue;}}
}void Server::slot_Disconnected(int descriptor) {
// 遍历找到并删除断开的通信套接字for(int i = 0; i < tcpClientSocketList.count(); ++i) {QTcpSocket *tmp = tcpClientSocketList.at(i);if(tmp->socketDescriptor() == descriptor) {tcpClientSocketList.removeAt(i);return;}}
}

相关文章:

Qt 网络通信

获取本机网络信息 &#xff08;1&#xff09;在 .pro 文件中加入 QT network&#xff08;2&#xff09; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QDebug> #include <QLabel> #include <QLineEdit> #include <QPu…...

基恩士软件的基本操作(五,日志记录与使用)

目录 基恩士是如何保存日志的&#xff1f; 如何使用日志功能 查看DM10的值1秒加1的记录日志 设定id与储存位置 软元件设定&#xff08; 日志ID有10个&#xff08;0~10&#xff09;&#xff0c;每一个ID最多添加512个软元件&#xff09; 设定触发 执行日志的梯形图程序 触…...

MySQL 8 手动安装后无法启动的问题解决

开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;&#xff08;…...

难怪被人卷了不知道啊!这么学自动化测试,一个星期就搞定了!!!

目前自动化测试并不属于新鲜的事物&#xff0c;或者说自动化测试的各种方法论已经层出不穷&#xff0c;但是&#xff0c;能够明白自动化测试并很好落地实施的团队还不是非常多&#xff0c;我们接来下用通俗的方式来介绍自动化测试…… 首先我们从招聘岗位需求说起。看近期的职…...

每日OJ题_算法_双指针⑦力扣15. 三数之和

目录 力扣15. 三数之和 解析代码 力扣15. 三数之和 难度 中等 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三…...

【计算机网络学习之路】日志和守护进程

文章目录 前言一. 日志介绍二. 简单日志1. 左字符串2. 右字符串 三. 守护进程1. ps -axj命令2. 会话扩展命令 3. 创建守护进程 结束语 前言 本系列文章是计算机网络学习的笔记&#xff0c;欢迎大佬们阅读&#xff0c;纠错&#xff0c;分享相关知识。希望可以与你共同进步。 本…...

foobar2000 突然无法正常输出DSD信号

之前一直在用foobar2000加外置dac听音乐&#xff0c;有一天突然发现听dsd的时候&#xff0c;dac面板显示输出的是PCM格式信号&#xff0c;而不是DSD信号&#xff0c;这让我觉得很奇怪&#xff0c;反复折腾了几次&#xff0c;卸载安装驱动什么的&#xff0c;依然如此&#xff0c…...

鸿蒙HarmonyOS 编辑器 下载 安装

好 各位 之前的文章 注册并实名认证华为开发者账号 我们基实名注册了华为的开发者账号 我们可以访问官网 https://developer.harmonyos.com/cn/develop/deveco-studio 在这里 直接就有我们编辑器的下载按钮 我们直接点击立即下载 这里 我们根据自己的系统选择要下载的系统 例…...

机器学习第13天:模型性能评估指标

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 文章目录 交叉验证 保留交叉验证 k-折交叉验证 留一交叉验证 混淆矩阵 精度与召回率 介绍 精度 召回率 区别 使用代码 偏差与方差 介绍 区…...

Elasticsearch基础优化

分片策略 分片和副本得设计为ES提供支付分布式和故障转移得特性&#xff0c;但不意味着分片和副本是可以无限分配&#xff0c; 而且索引得分片完成分配后由于索引得路由机制&#xff0c;不能重新修改分片数&#xff08;副本数可以动态修改&#xff09; 一个分片得底层为一个l…...

【Amazon】通过直接连接的方式导入 KubeSphere集群至KubeSphere主容器平台

文章目录 一、设置主集群方式一&#xff1a;使用 Web 控制台方式二&#xff1a;使用 Kubectl命令 二、在主集群中设置代理服务地址方式一&#xff1a;使用 Web 控制台方式二&#xff1a;使用 Kubectl命令 三、登录控制台验证四、准备成员集群方式一&#xff1a;使用 Web 控制台…...

三数之和问题

给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 示例 1&…...

【JavaEE】多线程 (2) --线程安全

目录 1. 观察线程不安全 2. 线程安全的概念 3. 线程不安全的原因 4. 解决之前的线程不安全问题 5. synchronized 关键字 - 监视器锁 monitor lock 5.1 synchronized 的特性 5.2 synchronized 使⽤⽰例 1. 观察线程不安全 package thread; public class ThreadDemo19 {p…...

关于点胶机那些事

总结一下点胶机技术要点&#xff1a; 1&#xff1a;不论多复杂的点胶机&#xff0c;简单点&#xff0c;可以简化为&#xff1a;1&#xff1a;运控 2&#xff1a;点胶&#xff0c;3&#xff1a;检测 运控的目的就是负责把针头移到面板对应的胶路上&#xff0c;点胶即就是排胶&…...

Python | CAP - 累积精度曲线分析案例

CAP通常被称为“累积精度曲线”&#xff0c;用于分类模型的性能评估。它有助于我们理解和总结分类模型的鲁棒性。为了直观地显示这一点&#xff0c;我们在图中绘制了三条不同的曲线&#xff1a; 一个随机的曲线&#xff08;random&#xff09;通过使用随机森林分类器获得的曲线…...

ubuntu22.04安装swagboot遇到的问题

一、基本情况 系统&#xff1a;u 22.04 python&#xff1a; 3.10 二、问题描述 swagboot官方提供的安装路径言简意赅:python3 -m pip install --user snagboot 当然安装python3和pip是基本常识&#xff0c;这里就不再赘述。 可是在安装的时候出现如下提示说 Failed buildin…...

python每日一题——8无重复字符的最长子串

题目 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示例 2: 输入: s “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串…...

【数据中台】开源项目(2)-Dbus数据总线

1 背景 企业中大量业务数据保存在各个业务系统数据库中&#xff0c;过去通常的同步数据的方法有很多种&#xff0c;比如&#xff1a; 各个数据使用方在业务低峰期各种抽取所需数据&#xff08;缺点是存在重复抽取而且数据不一致&#xff09; 由统一的数仓平台通过sqoop到各个…...

职场快速赢得信任

俗话说的好&#xff0c;有人的地方就有江湖。 国内不管是外企、私企、国企&#xff0c;职场环境都是变换莫测。 这里主要分享下怎么在职场中快速赢取信任。 1、找到让自己全面发展的方法 要知道&#xff0c;职场中话题是与他人交流的纽带&#xff0c;为了找到共同的话题&am…...

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)

目录 一、环境准备 1、创建Vue工程 2、安装依赖 2.1 安装项目所需要的vue依赖 2.2 安装element-plus依赖 2.2.1 安装 2.2.2 项目导入element-plus 2.3 安装axios依赖 2.4 安装sass依赖 3、目录调整 3.1 删除部分默认目录下文件 3.1.1 src/components下自动生成的…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 &#xff1a;开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置&#xff0c;将微信开发者工具放入到Hbuilder中&#xff0c; 打开后出现 如下 bug 解…...

自然语言处理——文本分类

文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益&#xff08;IG&#xff09; 分类器设计贝叶斯理论&#xff1a;线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别&#xff0c; 有单标签多类别文本分类和多…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...

字符串哈希+KMP

P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...

react更新页面数据,操作页面,双向数据绑定

// 路由不是组件的直接跳转use client&#xff0c;useEffect&#xff0c;useRouter&#xff0c;需3个结合&#xff0c; use client表示客户端 use client; import { Button,Card, Space,Tag,Table,message,Input } from antd; import { useEffect,useState } from react; impor…...