【QT】UDP通信QUdpSocket(单播、广播、组播)
目录
- 1. UDP通信概述
- 2. UDP消息传送的三种模式
- 3. QUdpSocket类的接口函数
- 4. UDP单播和广播代码示例
- 4.1 测试说明
- 4.2 MainWindow.h
- 4.3 MainWindow.cpp
- 4.4 界面展示
- 5. UDP组播代码示例
- 5.1 组播的特性
- 5.2 MainWindow.h
- 5.3 MainWindow.cpp
- 5.4 界面展示
1. UDP通信概述
UDP是无连接、不可靠、面向数据报(datagram)的协议,可以应用于对可靠性要求不高的场合。与TCP通信不同,UDP通信无需预先建立持久的socket连接,UDP每次发送数据报都需要指定目标地址和端口。
QUdpSocket以数据报传输数据,而不是以连续的数据流。发送数据报使用函数QUdpSocket::writeDatagram(),数据报的长度一般少于512字节,每个数据报包含发送者和接收者的IP地址和端口等信息。
UDP数据接收,首先要使用QUdpSocket::bind()绑定一个端口,绑定端口后,socket的状态会变为已绑定状态“BoundState”。当有数据报传入时,QudpSocket会自动发射readyRead()信号,在其槽函数中使用QUdpSocket::readDatagram()进行数据读取。abort()为解除绑定,解除后socket状态变为未连接状态“UnconnectedState”。
2. UDP消息传送的三种模式
单播模式(unicast):一个UDP客户端发送数据报到指定地址和端口的另一UDP客户端,是一对一的数据传输。
广播模式(broadcast):一个UDP客户端发出的数据报,在同一网络范围内其他所有的UDP客户端都可以收到。QUdpSocket支持IPv4广播。需要在数据报中指定接收端地址为QHostAddress::Broadcast,一般的广播地址是255.255.255.255。
组播模式(multicast):UDP客户端加入到另一个组播IP地址的多播组,成员向组播地址发送的数据报,其加入组播的所有成员都可以接收到,类似于QQ群功能。QUdpSocket::joinMulticastGroup()函数实现加入多播组的功能。
在单播、广播和多播模式下,UDP程序都是对等的,不像TCP通信分为客户端和服务端。
TCP通信只有单播模式。UDP通信虽然不能保证数据传输的准确性,但是具有灵活性,一般的即时通信软件都是基于UDP通信的。
3. QUdpSocket类的接口函数
bool bind(quint16 port = 0) 为UDP通信绑定一个端口
qint64 writeDatagram(QByteArray& datagram, QHostAddress& host, quint16 port) 向目标地址和端口的UDP客户端发送数据报,返回成功发送的字节数,数据报的长度一般不超过512字节。
bool hasPendingDatagrams() 当至少有一个数据报需要读取时,返回true
qint64 pendingDatagramSize() 返回第一个待读取的数据报的大小
qint64 readDatagram(char* data, qint64 maxSize) 读取一个数据报,返回成功读取的字节数
qint64 readDatagram(char* data, qint64 maxSize, QHostAddress* address, quint16* port) 读取一个数据报,返回成功读取的字节数。发送方的主机地址和端口存储在*address和*port中(除非指针为0)
bool joinMulticastGroup(QHostAddress& groupAddress) 加入一个多播组
bool leaveMulticastGroup(QHostAddress& groupAddress) 离开一个多播组
void abort() 终止当前连接并重置套接字。通常在析构函数中写入。与disconnectFromHost()不同,该函数立即关闭套接字,丢弃写入缓冲区中的任何挂起数据。
4. UDP单播和广播代码示例
4.1 测试说明
本实例实现UDP通信的单播和广播。两个实例可以运行在同一台计算机上,也可以运行在不同的计算机上。
这里的两个实例是运行在同一台计算机上,需要注意,在同一台计算机上运行时,两个实例需要绑定不同的端口。例如实例A绑定端口1600,实例B绑定端口3200,实例A向实例B发送数据报时,需要指定实例B的端口,这样实例B才能收到数据。
如果两个实例在不同的计算机上运行,则端口可以一样,因为IP地址不同了,不会导致绑定时发生冲突。一般的UDP通信程序都是在不同的计算机上运行的,约定一个固定的端口作为通信端口。
4.2 MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QAction>
#include <QComboBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QHostInfo>
#include <QLabel>
#include <QLineEdit>
#include <QMainWindow>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QSpinBox>
#include <QUdpSocket>
#include <QVBoxLayout>namespace Ui {class MainWindow;
}class MainWindow : public QMainWindow {Q_OBJECTpublic:explicit MainWindow(QWidget* parent = 0);~MainWindow();private slots:void slotActBindPort();void slotActUnbindPort();void slotActClearText();void slotActQuit();void slotSocketStateChanged(QAbstractSocket::SocketState socketState);void slotBtnSend();void slotBtnBroad();void slotSocketReadyRead(); //读取socket传入的数据private:Ui::MainWindow* ui;QAction* m_pActBindPort;QAction* m_pActUnbindPort;QAction* m_pActClearText;QAction* m_pActQuit;QWidget* m_pCentralWidget;QLabel* m_pLabBindPort;QLabel* m_PLabTargetAddr;QLabel* m_pLabTargetPort;QSpinBox* m_pSpinBindPort;QComboBox* m_pComboTargetAddr;QSpinBox* m_pSpinTargetPort;QLineEdit* m_pLineEdit;QPushButton* m_pBtnSend;QPushButton* m_pBtnBroad;QPlainTextEdit* m_pPlainText;QLabel* m_pLabState;QUdpSocket* m_pUdpSocket;QString getLocalIP();
};#endif // MAINWINDOW_H
4.3 MainWindow.cpp
#include "mainwindow.h"#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);this->setWindowIcon(QIcon(":/new/prefix1/res/TitleIcon.png"));this->setWindowTitle(QStringLiteral("UDP Send/Receiver"));//工具栏ui->mainToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);m_pActBindPort = new QAction(QIcon(":/new/prefix1/res/绑定端口.png"), QStringLiteral("绑定端口"), this);m_pActUnbindPort = new QAction(QIcon(":/new/prefix1/res/解除绑定.png"), QStringLiteral("结束绑定"), this);m_pActClearText = new QAction(QIcon(":/new/prefix1/res/清空文本.png"), QStringLiteral("清空文本"), this);m_pActQuit = new QAction(QIcon(":/new/prefix1/res/退出.png"), QStringLiteral("退出"), this);ui->mainToolBar->addAction(m_pActBindPort);ui->mainToolBar->addAction(m_pActUnbindPort);ui->mainToolBar->addSeparator();ui->mainToolBar->addAction(m_pActClearText);ui->mainToolBar->addSeparator();ui->mainToolBar->addAction(m_pActQuit);//界面布局m_pCentralWidget = new QWidget(this);QHBoxLayout* HLay1 = new QHBoxLayout;m_pLabBindPort = new QLabel(QStringLiteral("绑定端口"), m_pCentralWidget);m_pSpinBindPort = new QSpinBox(m_pCentralWidget);m_pSpinBindPort->setMinimum(1);m_pSpinBindPort->setMaximum(65535);m_pSpinBindPort->setValue(1600);m_PLabTargetAddr = new QLabel(QStringLiteral("目标地址"), m_pCentralWidget);m_pComboTargetAddr = new QComboBox(m_pCentralWidget);m_pLabTargetPort = new QLabel(QStringLiteral("目标端口"), m_pCentralWidget);m_pSpinTargetPort = new QSpinBox(m_pCentralWidget);m_pSpinTargetPort->setMinimum(1);m_pSpinTargetPort->setMaximum(65535);m_pSpinTargetPort->setValue(3200);HLay1->addWidget(m_pLabBindPort, 1, Qt::AlignRight);HLay1->addWidget(m_pSpinBindPort, 2);HLay1->addWidget(m_PLabTargetAddr, 1, Qt::AlignRight);HLay1->addWidget(m_pComboTargetAddr, 4);HLay1->addWidget(m_pLabTargetPort, 1, Qt::AlignRight);HLay1->addWidget(m_pSpinTargetPort, 2);QHBoxLayout* HLay2 = new QHBoxLayout;m_pLineEdit = new QLineEdit(m_pCentralWidget);m_pBtnSend = new QPushButton(QStringLiteral("发送消息"), m_pCentralWidget);m_pBtnBroad = new QPushButton(QStringLiteral("广播消息"), m_pCentralWidget);HLay2->addWidget(m_pLineEdit);HLay2->addWidget(m_pBtnSend);HLay2->addWidget(m_pBtnBroad);QVBoxLayout* VLay = new QVBoxLayout(m_pCentralWidget); //主布局必须设置parent,否则不会显示布局// QVBoxLayout* VLay = new QVBoxLayout();VLay->addLayout(HLay1);VLay->addLayout(HLay2);m_pPlainText = new QPlainTextEdit(m_pCentralWidget);VLay->addWidget(m_pPlainText);this->setCentralWidget(m_pCentralWidget);this->setLayout(VLay); //设置为窗体的主布。在指定了主布局的parent之后,这句话可有可无QString localIP = getLocalIP();this->setWindowTitle(this->windowTitle() + "---IP:" + localIP);m_pComboTargetAddr->addItem(localIP);m_pUdpSocket = new QUdpSocket(this);//状态栏m_pLabState = new QLabel(QStringLiteral("socket状态:"), this);m_pLabState->setMinimumWidth(150);ui->statusBar->addWidget(m_pLabState);// connectconnect(m_pActBindPort, &QAction::triggered, this, &MainWindow::slotActBindPort);connect(m_pActUnbindPort, &QAction::triggered, this, &MainWindow::slotActUnbindPort);connect(m_pActClearText, &QAction::triggered, this, &MainWindow::slotActClearText);connect(m_pActQuit, &QAction::triggered, this, &MainWindow::slotActQuit);connect(m_pBtnSend, &QPushButton::clicked, this, &MainWindow::slotBtnSend);connect(m_pBtnBroad, &QPushButton::clicked, this, &MainWindow::slotBtnBroad);connect(m_pUdpSocket, &QUdpSocket::stateChanged, this, &MainWindow::slotSocketStateChanged);connect(m_pUdpSocket, &QUdpSocket::readyRead, this, &MainWindow::slotSocketReadyRead);
}MainWindow::~MainWindow() {m_pUdpSocket->abort();delete m_pUdpSocket;m_pUdpSocket = nullptr;delete ui;
}void MainWindow::slotActBindPort() {quint16 port = m_pSpinBindPort->value(); //本机UDP端口if (m_pUdpSocket->bind(port)) {m_pPlainText->appendPlainText("**已成功绑定");m_pPlainText->appendPlainText("绑定端口:" + QString::number(m_pUdpSocket->localPort()));//使能m_pActBindPort->setEnabled(false);m_pActUnbindPort->setEnabled(true);} else {m_pPlainText->appendPlainText("绑定失败");}
}void MainWindow::slotActUnbindPort() {m_pUdpSocket->abort(); //解除绑定m_pPlainText->appendPlainText("**已解除绑定");m_pActBindPort->setEnabled(true);m_pActUnbindPort->setEnabled(false);
}void MainWindow::slotActClearText() { m_pPlainText->clear(); }void MainWindow::slotActQuit() {QMessageBox::StandardButton button = QMessageBox::question(this, "", "是否要退出?");if (button == QMessageBox::StandardButton::Yes)this->close();
}void MainWindow::slotSocketStateChanged(QAbstractSocket::SocketState socketState) {switch (socketState) {case QAbstractSocket::UnconnectedState: m_pLabState->setText("socket状态:UnconnectedState"); break;case QAbstractSocket::HostLookupState: m_pLabState->setText("socket状态:HostLookupState"); break;case QAbstractSocket::ConnectingState: m_pLabState->setText("socket状态:ConnectingState"); break;case QAbstractSocket::ConnectedState: m_pLabState->setText("socket状态:ConnectedState"); break;case QAbstractSocket::BoundState: m_pLabState->setText("socket状态:BoundState"); break;case QAbstractSocket::ClosingState: m_pLabState->setText("socket状态:ClosingState"); break;default: break;}
}void MainWindow::slotBtnSend() {QString msg = m_pLineEdit->text();QByteArray str = msg.toUtf8();QString targetIp = m_pComboTargetAddr->currentText(); //目标IPQHostAddress targetAddr(targetIp);quint16 targetPort = m_pSpinTargetPort->value(); //目标端口m_pUdpSocket->writeDatagram(str, targetAddr, targetPort);m_pPlainText->appendPlainText("[out] " + msg);m_pLineEdit->clear();m_pLineEdit->setFocus();
}void MainWindow::slotBtnBroad() {QString msg = m_pLineEdit->text();QByteArray str = msg.toUtf8();quint16 targetPort = m_pSpinTargetPort->value();m_pUdpSocket->writeDatagram(str, QHostAddress::Broadcast, targetPort);m_pPlainText->appendPlainText("[out] " + msg);m_pLineEdit->clear();m_pLineEdit->setFocus();
}void MainWindow::slotSocketReadyRead() {while (m_pUdpSocket->hasPendingDatagrams()) {QByteArray dataGram;dataGram.resize(m_pUdpSocket->pendingDatagramSize());QHostAddress peerAddress;quint16 peerPort;m_pUdpSocket->readDatagram(dataGram.data(), dataGram.size(), &peerAddress, &peerPort);QString str = dataGram.data();QString peer = "[From " + peerAddress.toString() + ":" + QString::number(peerPort) + "]";m_pPlainText->appendPlainText(peer + str);}
}QString MainWindow::getLocalIP() {QString hostName = QHostInfo::localHostName();QHostInfo hostInfo = QHostInfo::fromName(hostName);QString localIP = "";QList<QHostAddress> addrList = hostInfo.addresses();if (!addrList.isEmpty()) {for (int i = 0; i < addrList.size(); i++) {QHostAddress addr = addrList.at(i);if (QAbstractSocket::IPv4Protocol == addr.protocol()) {localIP = addr.toString();break;}}}return localIP;
}
4.4 界面展示

5. UDP组播代码示例
5.1 组播的特性
组播报文的目的地址使用D类IP地址,关于组播IP地址,有以下约定:
- 224.0.0.0 ~ 224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其他地址供路由协议使用。
- 224.0.1.0 ~ 224.0.1.255是公用组播地址,可以用于Internet。
- 224.0.2.0 ~ 238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效。
- 239.0.0.0 ~ 239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。所以,若是在家庭或办公室局域网内测试UDP组播功能,可以使用这些IP。
5.2 MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QAction>
#include <QComboBox>
#include <QHBoxLayout>
#include <QHostInfo>
#include <QLabel>
#include <QLineEdit>
#include <QMainWindow>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QRegExp>
#include <QSpinBox>
#include <QUdpSocket>
#include <QVBoxLayout>namespace Ui {class MainWindow;
}class MainWindow : public QMainWindow {Q_OBJECTpublic:explicit MainWindow(QWidget* parent = 0);~MainWindow();private slots:void slotActJoinMulti();void slotActLeaveMulti();void slotActClearText();void slotActQuit();void slotSocketStateChanged(QAbstractSocket::SocketState socketState);void slotBtnMultiMsg();void slotReadyRead();private:Ui::MainWindow* ui;QAction* m_pActJoinMulti;QAction* m_pActLeaveMulti;QAction* m_pActClearText;QAction* m_pActQuit;QWidget* m_pCentralWidget;QLabel* m_pLabPort;QLabel* m_pLabAddr;QSpinBox* m_pSpinPort;QComboBox* m_pComboAddr;QLineEdit* m_pLineEdit;QPushButton* m_pBtnSendMulti;QPlainTextEdit* m_pPlainText;QLabel* m_pLabState;QUdpSocket* m_pUdpSocket;QHostAddress m_multicastAddr;QString getLocalIP();
};#endif // MAINWINDOW_H
5.3 MainWindow.cpp
#include "mainwindow.h"#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);this->setWindowTitle(QStringLiteral("UDP Multicast"));//工具栏ui->mainToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);m_pActJoinMulti = new QAction(QIcon(":/new/prefix1/res/添加群组.png"), QStringLiteral("加入组播"), this);m_pActLeaveMulti = new QAction(QIcon(":/new/prefix1/res/退出群组.png"), QStringLiteral("退出组播"), this);m_pActClearText = new QAction(QIcon(":/new/prefix1/res/清空.png"), QStringLiteral("清空文本"), this);m_pActQuit = new QAction(QIcon(":/new/prefix1/res/退出.png"), QStringLiteral("退出"), this);ui->mainToolBar->addAction(m_pActJoinMulti);ui->mainToolBar->addAction(m_pActLeaveMulti);ui->mainToolBar->addSeparator();ui->mainToolBar->addAction(m_pActClearText);ui->mainToolBar->addSeparator();ui->mainToolBar->addAction(m_pActQuit);//界面布局m_pCentralWidget = new QWidget(this);m_pLabPort = new QLabel(QStringLiteral("组播端口"), m_pCentralWidget);m_pSpinPort = new QSpinBox(m_pCentralWidget);m_pSpinPort->setMinimum(1);m_pSpinPort->setMaximum(65535);m_pSpinPort->setValue(3200);m_pLabAddr = new QLabel(QStringLiteral("组播地址"), m_pCentralWidget);m_pComboAddr = new QComboBox(m_pCentralWidget);m_pComboAddr->setEditable(true); //下拉框可编辑输入m_pComboAddr->addItem("239.0.0.1");// 正则匹配 D类IP:224.0.0.0~239.255.255.255// .必须使用转义字符\,否则.会匹配任意字符// C++中"\"在字符串中表示要用"\\"// 是 - 不是 ~ ; 是[0-9]不是[0~9]QRegExp regExp("^(22[4-9]|23[0-9])(\\.((\\d)|([1-9]\\d)|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))){3}$");QValidator* pValidator = new QRegExpValidator(regExp, this);m_pComboAddr->setValidator(pValidator);QHBoxLayout* HLay1 = new QHBoxLayout();HLay1->addWidget(m_pLabPort, 1, Qt::AlignRight);HLay1->addWidget(m_pSpinPort, 1);HLay1->addWidget(m_pLabAddr, 1, Qt::AlignRight);HLay1->addWidget(m_pComboAddr, 2);m_pLineEdit = new QLineEdit(m_pCentralWidget);m_pBtnSendMulti = new QPushButton(QStringLiteral("组播消息"), m_pCentralWidget);QHBoxLayout* HLay2 = new QHBoxLayout();HLay2->addWidget(m_pLineEdit, 4);HLay2->addWidget(m_pBtnSendMulti, 1);m_pPlainText = new QPlainTextEdit(m_pCentralWidget);QVBoxLayout* VLay = new QVBoxLayout(m_pCentralWidget);VLay->addLayout(HLay1);VLay->addLayout(HLay2);VLay->addWidget(m_pPlainText);this->setCentralWidget(m_pCentralWidget);this->setLayout(VLay);//状态栏m_pLabState = new QLabel(QStringLiteral("socket状态:"), this);m_pLabState->setMinimumWidth(150);ui->statusBar->addWidget(m_pLabState);QString str = getLocalIP();this->setWindowTitle(this->windowTitle() + "---IP:" + str);m_pUdpSocket = new QUdpSocket(this);m_pUdpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 1);// connectconnect(m_pActJoinMulti, &QAction::triggered, this, &MainWindow::slotActJoinMulti);connect(m_pActLeaveMulti, &QAction::triggered, this, &MainWindow::slotActLeaveMulti);connect(m_pActClearText, &QAction::triggered, this, &MainWindow::slotActClearText);connect(m_pActQuit, &QAction::triggered, this, &MainWindow::slotActQuit);connect(m_pUdpSocket, &QUdpSocket::stateChanged, this, &MainWindow::slotSocketStateChanged);connect(m_pBtnSendMulti, &QPushButton::clicked, this, &MainWindow::slotBtnMultiMsg);connect(m_pUdpSocket, &QUdpSocket::readyRead, this, &MainWindow::slotReadyRead);
}MainWindow::~MainWindow() { delete ui; }void MainWindow::slotActJoinMulti() {QString ip = m_pComboAddr->currentText();m_multicastAddr = QHostAddress(ip);quint16 multicastPort = m_pSpinPort->value();if (m_pUdpSocket->bind(QHostAddress::AnyIPv4, multicastPort, QUdpSocket::ShareAddress)) {m_pUdpSocket->joinMulticastGroup(m_multicastAddr); //加入多播组m_pPlainText->appendPlainText("**加入组播成功");m_pPlainText->appendPlainText("**组播地址IP:" + ip);m_pPlainText->appendPlainText("**绑定端口:" + QString::number(multicastPort));m_pActJoinMulti->setEnabled(false);m_pActLeaveMulti->setEnabled(true);m_pComboAddr->setEditable(false);} else {m_pPlainText->appendPlainText("**绑定端口失败");}
}void MainWindow::slotActLeaveMulti() {m_pUdpSocket->leaveMulticastGroup(m_multicastAddr); //退出组播m_pUdpSocket->abort(); //解除绑定m_pActJoinMulti->setEnabled(true);m_pActLeaveMulti->setEnabled(false);m_pComboAddr->setEnabled(true);m_pComboAddr->setEditable(true);m_pPlainText->appendPlainText("**已退出组播,解除端口绑定");
}void MainWindow::slotActClearText() { m_pPlainText->clear(); }void MainWindow::slotActQuit() {QMessageBox::StandardButton button = QMessageBox::question(this, "", "是否退出?");if (QMessageBox::StandardButton::Yes == button) {this->close();}
}void MainWindow::slotSocketStateChanged(QAbstractSocket::SocketState socketState) {// case并不包含所有的情况,因为没有写listening的情况,所以就需要写defaultswitch (socketState) {case QAbstractSocket::UnconnectedState: m_pLabState->setText("socket状态:UnconnectedState"); break;case QAbstractSocket::HostLookupState: m_pLabState->setText("socket状态:HostLookupState"); break;case QAbstractSocket::ConnectingState: m_pLabState->setText("socket状态:ConnectingState"); break;case QAbstractSocket::ConnectedState: m_pLabState->setText("socket状态:ConnectedState"); break;case QAbstractSocket::BoundState: m_pLabState->setText("socket状态:BoundState"); break;case QAbstractSocket::ClosingState: m_pLabState->setText("socket状态:ClosingState"); break;default: break;}
}void MainWindow::slotBtnMultiMsg() {QString msg = m_pLineEdit->text();QByteArray str = msg.toUtf8();quint16 multiPort = m_pSpinPort->value();m_pUdpSocket->writeDatagram(str, m_multicastAddr, multiPort);m_pPlainText->appendPlainText("[multicast] " + msg);m_pLineEdit->clear();m_pLineEdit->setFocus();
}void MainWindow::slotReadyRead() {while (m_pUdpSocket->hasPendingDatagrams()) {QByteArray dataGram;dataGram.resize(m_pUdpSocket->pendingDatagramSize());QHostAddress peerAddr;quint16 peerPort;m_pUdpSocket->readDatagram(dataGram.data(), dataGram.size(), &peerAddr, &peerPort);QString str = dataGram.data();QString peer = "[From " + peerAddr.toString() + ":" + QString::number(peerPort) + "] ";m_pPlainText->appendPlainText(peer + str);qDebug() << m_pUdpSocket->peerAddress();qDebug() << m_pUdpSocket->localAddress().toString();qDebug() << m_pUdpSocket->localPort();}
}QString MainWindow::getLocalIP() {QString localName = QHostInfo::localHostName();QHostInfo hostInfo = QHostInfo::fromName(localName);QList<QHostAddress> addrList = hostInfo.addresses();QString localIP = "";if (!addrList.isEmpty()) {for (int i = 0; i < addrList.size(); i++) {QHostAddress addr = addrList.at(i);if (QAbstractSocket::IPv4Protocol == addr.protocol()) {localIP = addr.toString();break;}}}return localIP;
}
5.4 界面展示

相关文章:
【QT】UDP通信QUdpSocket(单播、广播、组播)
目录1. UDP通信概述2. UDP消息传送的三种模式3. QUdpSocket类的接口函数4. UDP单播和广播代码示例4.1 测试说明4.2 MainWindow.h4.3 MainWindow.cpp4.4 界面展示5. UDP组播代码示例5.1 组播的特性5.2 MainWindow.h5.3 MainWindow.cpp5.4 界面展示1. UDP通信概述 UDP是无连接、…...
【Java】properties 和 yml 的区别
文章目录properties和yml的区别① 定义和定位不同② 语法不同③ yml更好的配置多种数据类型④ yml可以跨语言⑤ 总结properties和yml的区别 这几天刚好看到Spring Boot当中有两种配置文件的方式,但是这两种配置方式有什么区别呢? properties和yml都是S…...
percona软件介绍 、 innobackupex备份与恢复
1. 常用的mysql备份工具 物理备份缺点: 跨平台差。备份时间长、冗余备份、浪费存储空间。 解释如下:如Linux操作系统和Windows操作系统之间,由于文件系统不一样,如Linux操作系统的文件系统是ext4、xfs,Windows操作系统…...
Towards Adversarial Attack on Vision-Language Pre-training Models
摘要虽然视觉-语言预训练模型(VLP)在各种视觉-语言(VL)任务上表现出革命性的改进,但关于其对抗鲁棒性的研究在很大程度上仍未被探索。本文研究了常用VLP模型和VL任务的对抗性攻击。首先,我们分析了不同设置下对抗性攻击的性能。通过研究不同扰动对象和攻…...
2022年最新数据库调查报告:超八成DBA月薪过万,你拖后腿了吗?
数据库管理员属于IT行业高薪职业的一种,近几年关于数据库管理员的薪资统计文章也层出不穷,那么当前,DBA们的薪资究竟到达了怎样的水平呢?墨天轮数据社区发布最新《2022年墨天轮数据库大调查报告》,数据显示超八成DBA月…...
ESP-C3入门10. 创建TCP Client
ESP-C3入门10. 创建TCP Client一、创建 tcp client的一般步骤1. 创建 tcp 套接字2. 配置服务器地址3. 连接服务器4. 发送数据5. 接收数据6. 关闭套接字二、创建tcp_client任务三、示例代码1. tcpClient.h2. tcpClient.c3. main.c一、创建 tcp client的一般步骤 本文示例使用的…...
【Vue】浅谈vue2、vue3响应式原理,vue中数组的响应式,响应式常见问题分析
前言:此处响应式指的是数据响应式变化,而不是页面的响应式布局,页面的响应式布局在我的其他文章中有提到。 一、什么是vue响应式 Vue 最标志性的功能就是其低侵入性的响应式系统。组件状态都是由响应式的 JavaScript 对象组成的。当更改它们…...
股航顶峰先锋一号
{选股} TT:MA(C,30)>MA(C,60) AND MA(C,60)>MA(C,120);{均线多头} DD:C>REF(C,1);{收阳线} QQ:V>REF(V,1);{放量}; TT1:COUNT(L<MA(C,13),5)1; TT2:(C-REF(C,1))/REF(C,1)*100>3; DD1:V>REF(V,1)*2 AND C>REF(C,1); DD2:TT1 AND 0<MA(C,13)AND TT2 …...
MYSQL安装部署--Linux 仓库安装
声明 :# 此次我们安装的 MYSQL 版本是 8.0.32 版本 我们本次安装 MYSQL 总共要介绍 四种方式 # 仓库安装# 本地安装# 容器安装# 源码安装我们本篇介绍的是 仓库安装 仓库安装 下载 MYSQL 安装包 # MYSQL 安装,我们都是基于 MYSQL 官方网站里进行下载~&a…...
NFS服务器搭建
NFS服务器搭建1. NFS简介2. NFS工作原理3. 配置NFS服务端3.1 启动服务3.2 修改配置文件4. 配置NFS客户端1. NFS简介 NFS是Network File System的简写,即网络文件系统. 网络文件系统是FreeBSD支持的文件系统中的一种,也被称为NFS。 NFS允许一个系统在网络上与他人共…...
【数据挖掘实战】——航空公司客户价值分析(K-Means聚类案例)
目录 一、背景和挖掘目标 1、RFM模型缺点分析 2、原始数据情况 3、挖掘目标 二、分析方法与过程 1、初步分析:提出适用航空公司的LRFMC模型 2、总体流程 第一步:数据抽取 第二步:探索性分析 第三步:数据预处理 第四步&…...
AnlogicFPGA-IO引脚约束设置
(https://www.eefocus.com/article/472120.html此链接是一篇关于XillinxFPGA的IO的状态分析,希望自己也要能了解到AnLogic的IO状态并有对此问题的分析能力) 1、DriveStrength: 驱动强度,即最大能驱动的电流大小(见带负…...
Java SSM 笔记(一)重置版
Spring核心技术 **前置课程要求:**请各位小伙伴先完成《JavaWeb》篇、《Java 9-17新特性》篇视频教程之后,再来观看此教程。 **建议:**对Java开发还不是很熟悉的同学,最好先花费半个月到一个月时间大量地去编写小项目࿰…...
centos安装java,目录授权
centos安装java (1)查看可安装版本: yum -y list java* 安装:sudo yum -y install java-17-openjdk.x86_64 验证:java –version (2)二进制安装:下载:wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.…...
【大数据】HADOOP-YARN容量调度器多队列配置详解实战
简介 Capacity调度器具有以下的几个特性: 层次化的队列设计,这种层次化的队列设计保证了子队列可以使用父队列设置的全部资源。这样通过层次化的管理,更容易合理分配和限制资源的使用。容量保证,队列上都会设置一个资源的占比&a…...
加密技术在android系统安全中的应用
前言android 系统安全内容总结 1、算法基础 算法基础参照linux的全盘加密与文件系统加密在android中的应用的2、预备知识 android系统安全特性用到加密算法的如下表:...
KNN&K-means从入门到实战
作者:王同学 来源:投稿 编辑:学姐 1. 基本概念 1.1 KNN k近邻法(k-nearest neighbor,k-NN)是一种基本分类与回归方法。 k近邻法的输入为实例的特征向量对应于特征空间的点;输出为实例的类别&…...
SpringBoot整合RabbitMQ
SpringBoot整合RabbitMQ,生产者 (1)创建maven项目 (2)引入依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><versi…...
Hive---安装教程
Hive安装教程 Hive属于Hadoop生态圈,所以Hive必须运行在Hadoop上 文章目录Hive安装教程上传安装包解压并且更名修改 /etc/profile创建hive-site.xml将mysql的jar包放入Hive库中开启刷新配置文件hadoop开启mysql初始化启动hive上传安装包 将安装包上传到/opt/insta…...
MySQL作业四
学生表:Student (Sno, Sname, Ssex , Sage, Sdept) 学号,姓名,性别,年龄,所在系 Sno为主键 课程表:Course (Cno, Cname,) 课程号,课程名 Cno为主键 学生选课表:SC (Sno, Cno, Score)…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
