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

【QT】QT中的网络编程(TCP 和 UDP通信)

QT中的网络编程(TCP 和 UDP通信)

  • 1.tcp
    • 1.1 tcp通信
      • 1.1.1 相比linux中tcp通信:
      • 1.1.2 QT中的tcp通信:
    • 1.2 tcp通信流程
      • 1.2.1 服务器流程:
        • 1.2.1.1 示例代码
        • 1.2.1.2 现象
      • 1.2.2 客户端流程:
        • 1.2.2.1 示例代码
        • 1.2.2.2 现象:
    • 1.3 获取对方的ip和端口号
      • 1.3.1 示例代码(同服务器客户端代码)
    • 1.4 多个客户端连接服务器
      • 1.4.1 示例代码:多个客户端与服务器之间的通信
        • 服务器代码
        • 客户端1代码:(客户端代码基本相同,只是窗口标题和端口号不一样)
        • 客户端2代码:
        • 客户端3代码:
      • 1.4.2 现象:
    • 1.5 判断对方断开连接
      • 1.5.1 示例代码:
  • 2. udp
    • 2.1 udp通信流程
      • 2.1.1 发送端:
        • 2.1.1.1 示例代码:
      • 2.1.2 接收端:
        • 2.1.2.1 示例代码
        • 2.1.2.2 现象:
    • 2.2 bind需要注意的问题

注意:使用QT中的网络编程,必须在.pro文件中添加 QT += network

1.tcp

1.1 tcp通信

1.1.1 相比linux中tcp通信:

服务器: socket --》bind --》listen --》accept --》read/write --》close
客户端: socket --》bind --》connect --》read/write --》close

1.1.2 QT中的tcp通信:

涉及到两个类:
QTcpServer --》表示服务器
QTcpSocket --》表示套接字

1.2 tcp通信流程

1.2.1 服务器流程:

第一步: 创建QTcpServer的对象,调用listen方法(绑定ip和端口号,顺便监听)//构造函数QTcpServer::QTcpServer(QObject *parent = Q_NULLPTR)参数:parent --this指针bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0)返回值:成功 true 失败 false参数:address --》要绑定的ip地址QHostAddress::QHostAddress(const QString &address)参数:address --》要绑定的ip地址port --》要绑定的端口号
第二步:如果有新的客户端连接服务器,QTcpServer的对象会自动触发newConnection信号,程序员必须关联这个信号,在自定义的槽函数中实现代码逻辑(产生跟这个客户端对应的套接字)[signal] void QTcpServer::newConnection()QTcpSocket *QTcpServer::nextPendingConnection()返回值: QTcpSocket *目前连接成功的客户端套接字
第三步:使用刚才产生的那个套接字跟客户端通信发送信息:qint64 QTcpSocket::write(const QByteArray &byteArray)接收信息:QByteArray QTcpSocket::readAll()QByteArray QTcpSocket::read(qint64 maxSize)注意:如果对方有发送信息过来,不能直接调用read/readAll接收如果对方有发送信息过来,QTcpSocket的对象会自动触发readyRead()信号,程序员在自定义的槽函数里面调用read/readAll接收信息即可
第四步:关闭套接字close()

图示:
在这里插入图片描述

1.2.1.1 示例代码
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();public slots:void newLink();void recvClientMsg();void clientUnlink();private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QTcpServer *TcpServer;QTcpSocket *newTcpSocket;
};
#endif // WIDGET_H// widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 给主窗口设置标题this->setWindowTitle("服务器");// 1.初始化QTcpServer对象TcpServer = new QTcpServer(this);// 2.绑定并监听TcpServer->listen(QHostAddress("192.168.10.7"), 10000);// 3.当有新的客户端连接时,会长生newConnection信号,需要主动关联newConnection信号connect(TcpServer, &QTcpServer::newConnection, this, &Widget::newLink);
}Widget::~Widget()
{delete ui;
}// 跟newConnection信号对应的槽函数
void Widget::newLink()
{qDebug()<<"有客户端连接到服务器";// 调用nextPendingConnection()产生新的套接字newTcpSocket = TcpServer->nextPendingConnection();//获取对方(客户端)的ip和端口号QString clientIP = newTcpSocket->peerAddress().toString();quint16 clientPort = newTcpSocket->peerPort();//拼接ip和端口号在标签上显示QString clientIPAndPort = QString("%1@%2").arg(clientIP).arg(clientPort);ui->label->setText(clientIPAndPort);//在横向列表框中显示ui->listWidget->addItem(clientIPAndPort);// 关联readyRead信号,在槽函数中接收对方发送过来的信息connect(newTcpSocket, &QIODevice::readyRead, this, &Widget::recvClientMsg);// 关联disconnected()信号,判断客户端是否断开连接connect(newTcpSocket, &QAbstractSocket::disconnected, this, &Widget::clientUnlink);
}//发送信息的槽函数
void Widget::on_pushButton_clicked()
{// 获取文本编辑框中输入的内容QString serverSendInfo = ui->textEdit->toPlainText();// 4.把内容发送给客户端newTcpSocket->write(serverSendInfo.toUtf8());
}//接收客户端信息
void Widget::recvClientMsg()
{// 在套接字中读取到的信息QByteArray clientMsg = newTcpSocket->readAll();//在文本浏览框中显示出来ui->textBrowser->setText(clientMsg);
}// 客户端断开连接
void Widget::clientUnlink()
{qDebug() << "客户端断开连接";
}
1.2.1.2 现象

在这里插入图片描述

1.2.2 客户端流程:

第一步:创建QTcpSocket的对象,调用bind函数绑定ip和端口号//构造函数QTcpSocket::QTcpSocket(QObject *parent = nullptr)参数:parent --this指针bool QAbstractSocket::bind(const QHostAddress &address, quint16 port = 0)返回值: 成功 true 失败 false参数: address --》要绑定的ip地址port --》要绑定的端口号
第二步:连接服务器void QAbstractSocket::connectToHost(const QHostAddress &address, quint16 port)参数:address --》服务器的ip地址port --》服务器的端口号
第三步:使用刚才新建的那个套接字跟服务器通信发送信息:qint64 QTcpSocket::write(const QByteArray &byteArray)接收信息:QByteArray QTcpSocket::readAll()QByteArray QTcpSocket::read(qint64 maxSize)注意:如果对方有发送信息过来,不能直接调用read/readAll接收如果对方有发送信息过来,QTcpSocket的对象会自动触发readyRead(),程序员在自定义的槽函数里面调用read/readAll接收信息即可
第四步:关闭套接字close()

图示:
在这里插入图片描述

1.2.2.1 示例代码
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_btn_connectServer_clicked();void on_btn_sendMsgServer_clicked();void recvServerMsg();void serverUnlink();private:Ui::Widget *ui;QTcpSocket *clientSocket;
};
#endif // WIDGET_H// widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 给主窗口设置标题this->setWindowTitle("客户端");// 1.初始化QTcpSocket对象clientSocket = new QTcpSocket(this);// 2.绑定客户端的IP和端口号clientSocket->bind(QHostAddress("192.168.10.7"), 20000);// 关联disconnected()信号,判断客户端是否断开连接connect(clientSocket, &QAbstractSocket::disconnected, this, &Widget::serverUnlink);
}Widget::~Widget()
{delete ui;
}// 3.连接到服务器
void Widget::on_btn_connectServer_clicked()
{// 获取服务器的ip 和端口号QString serverIP = ui->lineEdit_inServerIP->text();QString serverPort = ui->lineEdit_inServerPort->text();// 连接服务器clientSocket->connectToHost(QHostAddress(serverIP), serverPort.toInt());// 关联 readyRead 信号,在槽函数中接收服务器发送过来的信息connect(clientSocket, &QIODevice::readyRead, this, &Widget::recvServerMsg);
}// 4.发送信息到服务器
void Widget::on_btn_sendMsgServer_clicked()
{// 读取发送文本框的内容QString sendStr = ui->textEdit->toPlainText();// 发送给服务器clientSocket->write(sendStr.toUtf8());
}// 接收服务器发送的信息
void Widget::recvServerMsg()
{// 在套接字文件中读取到的信息QByteArray recvMSg = clientSocket->readAll();// 在文本浏览框中显示ui->textBrowser->setText(recvMSg);
}// 判断服务器断开连接
void Widget::serverUnlink()
{qDebug() << "服务器断开连接";
}
1.2.2.2 现象:

现象同1.2.1.2

1.3 获取对方的ip和端口号

QHostAddress QAbstractSocket::peerAddress() const返回值:对方的ipQString QHostAddress::toString() const返回值:把QHostAddress转换字符串格式ip地址
quint16 QAbstractSocket::peerPort() const返回值:对方的端口号

1.3.1 示例代码(同服务器客户端代码)

//获取对方(客户端)的ip和端口号
QString clientIP = newTcpSocket->peerAddress().toString();
quint16 clientPort = newTcpSocket->peerPort();
//拼接ip和端口号在标签上显示
QString clientIPAndPort = QString("%1@%2").arg(clientIP).arg(clientPort);
ui->label->setText(clientIPAndPort);
//在横向列表框中显示
ui->listWidget->addItem(clientIPAndPort);

1.4 多个客户端连接服务器

//给主窗口设置标题
void QMainWindow::setWindowTitle(const QString &)
// 例如
this->setWindowTitle("服务器");
this->setWindowTitle("客户端");
//复制了客户端的代码,若不想改文件名时,运行同一个文件产生的临时文件名会相同,导致客户端程序只能运行一个
解决办法:需要去项目(QT开发环境的左侧像扳手的一样的图标),取消勾选shadow build的路径(这个路径是编译产生的临时文件所在的路径),
此时生成的临时文件就是与源文件同一个目录

在这里插入图片描述

1.4.1 示例代码:多个客户端与服务器之间的通信

服务器代码
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QListWidgetItem>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();public slots:void newLink();void recvClientMsg();void clientUnlink();private slots:void on_pushButton_clicked();void on_listWidget_itemDoubleClicked(QListWidgetItem *item);private:Ui::Widget *ui;QTcpServer *TcpServer;QTcpSocket *newTcpSocket;QList<QTcpSocket *> ServerSocketList;QString clientStr;
};
#endif // WIDGET_H// widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 给主窗口设置标题this->setWindowTitle("服务器");// 1.初始化QTcpServer对象TcpServer = new QTcpServer(this);// 2.绑定并监听TcpServer->listen(QHostAddress("192.168.10.7"), 10000);// 3.当有新的客户端连接时,会长生newConnection信号,需要主动关联newConnection信号connect(TcpServer, &QTcpServer::newConnection, this, &Widget::newLink);
}Widget::~Widget()
{delete ui;
}// 跟newConnection信号对应的槽函数
void Widget::newLink()
{qDebug()<<"有客户端连接到服务器";// 调用nextPendingConnection()产生新的套接字newTcpSocket = TcpServer->nextPendingConnection();//获取对方(客户端)的ip和端口号QString clientIP = newTcpSocket->peerAddress().toString();quint16 clientPort = newTcpSocket->peerPort();//拼接ip和端口号在标签上显示QString clientIPAndPort = QString("%1@%2").arg(clientIP).arg(clientPort);ui->label->setText(clientIPAndPort);//在横向列表框中显示ui->listWidget->addItem(clientIPAndPort);// 关联readyRead信号,在槽函数中接收对方发送过来的信息connect(newTcpSocket, &QIODevice::readyRead, this, &Widget::recvClientMsg);// 关联disconnected()信号,判断客户端是否断开连接connect(newTcpSocket, &QAbstractSocket::disconnected, this, &Widget::clientUnlink);// 把当前连接成功的客户端套接字存放到容器ServerSocketList.push_back(newTcpSocket);
}//发送信息的槽函数
void Widget::on_pushButton_clicked()
{// 获取文本编辑框中输入的内容QString serverSendInfo = ui->textEdit->toPlainText();// 由于所有连接成功的客户端套接字都存放到了容器socklist里面// 遍历容器,找到双击的那个客户端对应的套接字int i;for (i = 0;i < ServerSocketList.size(); i++) {QString ip = ServerSocketList[i]->peerAddress().toString(); // ip地址quint16 port = ServerSocketList[i]->peerPort();         // 端口号QString curStr = QString("%1@%2").arg(ip).arg(port);if (curStr == clientStr){break; // 找到了双击的那个客户端}}// 4.把内容发送给客户端ServerSocketList[i]->write(serverSendInfo.toUtf8());
}//接收客户端信息 (多个信号共用一个槽函数)
void Widget::recvClientMsg()
{// 获取信号的发送者QObject *signalSender = sender();// 转换成QTcpSocket指针-->即当前发送消息的客户端QTcpSocket *curSocket = qobject_cast<QTcpSocket *>(signalSender);// 在套接字中读取到的信息QByteArray clientMsg = curSocket->readAll();QString clientMsgStr(clientMsg);//获取对方(客户端)的ip和端口号QString ip = curSocket->peerAddress().toString(); // ip地址quint16 port = curSocket->peerPort();         // 端口号//拼接ip和端口号在标签上显示QString curStr = QString("%1@%2发来的消息:@%3").arg(ip).arg(port).arg(clientMsgStr);//在文本浏览框中显示出来ui->textBrowser->append(curStr);
}// 客户端断开连接--->把对应的套接字删除在列表框中移除
void Widget::clientUnlink()
{
//    qDebug() << "客户端断开连接";// 获取断开连接的信号的发送者QObject *signalSender = sender();// 转换成QTcpSocket指针-->即当前发送消息的客户端QTcpSocket *curSocket = qobject_cast<QTcpSocket *>(signalSender);// 获取对方(客户端)的ip和端口号QString ip = curSocket->peerAddress().toString(); // ip地址quint16 port = curSocket->peerPort();         // 端口号// 拼接ip和端口号,这个就是要删除的客户端QString delStr = QString("%1@%2").arg(ip).arg(port);// 从容器里面把对应的套接字删除ServerSocketList.removeOne(curSocket);// 从横向列表框中删除对应的客户端信息// 查找列表项QList<QListWidgetItem*> curFindItem= ui->listWidget->findItems(delStr, Qt::MatchContains);//通过列表项得到索引号int index = ui->listWidget->row(curFindItem[0]);// 删除对应的客户端信息ui->listWidget->takeItem(index);
}
// 双击某个客户端
void Widget::on_listWidget_itemDoubleClicked(QListWidgetItem *item)
{//获取列表项的文本内容(某个客户端的  ip@端口)clientStr = item->text();
}
客户端1代码:(客户端代码基本相同,只是窗口标题和端口号不一样)
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_btn_connectServer_clicked();void on_btn_sendMsgServer_clicked();void recvServerMsg();void serverUnlink();private:Ui::Widget *ui;QTcpSocket *clientSocket;
};
#endif // WIDGET_H// widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 给主窗口设置标题this->setWindowTitle("客户端1");// 1.初始化QTcpSocket对象clientSocket = new QTcpSocket(this);// 2.绑定客户端的IP和端口号clientSocket->bind(QHostAddress("192.168.10.7"), 15000);// 关联disconnected()信号,判断客户端是否断开连接connect(clientSocket, &QAbstractSocket::disconnected, this, &Widget::serverUnlink);
}Widget::~Widget()
{delete ui;
}// 3.连接到服务器
void Widget::on_btn_connectServer_clicked()
{// 获取服务器的ip 和端口号QString serverIP = ui->lineEdit_inServerIP->text();QString serverPort = ui->lineEdit_inServerPort->text();// 连接服务器clientSocket->connectToHost(QHostAddress(serverIP), serverPort.toInt());// 关联 readyRead 信号,在槽函数中接收服务器发送过来的信息connect(clientSocket, &QIODevice::readyRead, this, &Widget::recvServerMsg);
}// 4.发送信息到服务器
void Widget::on_btn_sendMsgServer_clicked()
{// 读取发送文本框的内容QString sendStr = ui->textEdit->toPlainText();// 发送给服务器clientSocket->write(sendStr.toUtf8());
}// 接收服务器发送的信息
void Widget::recvServerMsg()
{// 在套接字文件中读取到的信息QByteArray recvMSg = clientSocket->readAll();// 在文本浏览框中显示ui->textBrowser->setText(recvMSg);
}// 判断服务器断开连接
void Widget::serverUnlink()
{qDebug() << "服务器断开连接";
}
客户端2代码:
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_btn_connectServer_clicked();void on_btn_sendMsgServer_clicked();void recvServerMsg();void serverUnlink();private:Ui::Widget *ui;QTcpSocket *clientSocket;
};
#endif // WIDGET_H// widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 给主窗口设置标题this->setWindowTitle("客户端2");// 1.初始化QTcpSocket对象clientSocket = new QTcpSocket(this);// 2.绑定客户端的IP和端口号clientSocket->bind(QHostAddress("192.168.10.7"), 16000);// 关联disconnected()信号,判断客户端是否断开连接connect(clientSocket, &QAbstractSocket::disconnected, this, &Widget::serverUnlink);
}Widget::~Widget()
{delete ui;
}// 3.连接到服务器
void Widget::on_btn_connectServer_clicked()
{// 获取服务器的ip 和端口号QString serverIP = ui->lineEdit_inServerIP->text();QString serverPort = ui->lineEdit_inServerPort->text();// 连接服务器clientSocket->connectToHost(QHostAddress(serverIP), serverPort.toInt());// 关联 readyRead 信号,在槽函数中接收服务器发送过来的信息connect(clientSocket, &QIODevice::readyRead, this, &Widget::recvServerMsg);
}// 4.发送信息到服务器
void Widget::on_btn_sendMsgServer_clicked()
{// 读取发送文本框的内容QString sendStr = ui->textEdit->toPlainText();// 发送给服务器clientSocket->write(sendStr.toUtf8());
}// 接收服务器发送的信息
void Widget::recvServerMsg()
{// 在套接字文件中读取到的信息QByteArray recvMSg = clientSocket->readAll();// 在文本浏览框中显示ui->textBrowser->setText(recvMSg);
}// 判断服务器断开连接
void Widget::serverUnlink()
{qDebug() << "服务器断开连接";
}
客户端3代码:
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_btn_connectServer_clicked();void on_btn_sendMsgServer_clicked();void recvServerMsg();void serverUnlink();private:Ui::Widget *ui;QTcpSocket *clientSocket;
};
#endif // WIDGET_H// widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 给主窗口设置标题this->setWindowTitle("客户端3");// 1.初始化QTcpSocket对象clientSocket = new QTcpSocket(this);// 2.绑定客户端的IP和端口号clientSocket->bind(QHostAddress("192.168.10.7"), 17000);// 关联disconnected()信号,判断客户端是否断开连接connect(clientSocket, &QAbstractSocket::disconnected, this, &Widget::serverUnlink);
}Widget::~Widget()
{delete ui;
}// 3.连接到服务器
void Widget::on_btn_connectServer_clicked()
{// 获取服务器的ip 和端口号QString serverIP = ui->lineEdit_inServerIP->text();QString serverPort = ui->lineEdit_inServerPort->text();// 连接服务器clientSocket->connectToHost(QHostAddress(serverIP), serverPort.toInt());// 关联 readyRead 信号,在槽函数中接收服务器发送过来的信息connect(clientSocket, &QIODevice::readyRead, this, &Widget::recvServerMsg);
}// 4.发送信息到服务器
void Widget::on_btn_sendMsgServer_clicked()
{// 读取发送文本框的内容QString sendStr = ui->textEdit->toPlainText();// 发送给服务器clientSocket->write(sendStr.toUtf8());
}// 接收服务器发送的信息
void Widget::recvServerMsg()
{// 在套接字文件中读取到的信息QByteArray recvMSg = clientSocket->readAll();// 在文本浏览框中显示ui->textBrowser->setText(recvMSg);
}// 判断服务器断开连接
void Widget::serverUnlink()
{qDebug() << "服务器断开连接";
}

1.4.2 现象:

在这里插入图片描述

1.5 判断对方断开连接

原理:如果对方断开连接,QTcpSocket的对象会自动触发disconnected()信号,程序员自己关联这个信号,在槽函数里面写代码处理断开以后的处理
[signal] void QAbstractSocket::disconnected()

1.5.1 示例代码:

跟newConnection信号对应的槽函数中添加连接信号

// 关联disconnected()信号,判断客户端是否断开连接
connect(newTcpSocket, &QAbstractSocket::disconnected, this, &Widget::clientUnlink);

2. udp

2.1 udp通信流程

2.1.1 发送端:

第一步:创建QUdpSocket套接字对象,调用bind绑定ip和端口号QUdpSocket::QUdpSocket(QObject *parent = nullptr)bool QAbstractSocket::bind(const QHostAddress &address, quint16 port = 0)返回值: 成功 true 失败 false参数: address --》要绑定的ip地址port --》要绑定的端口号 
第二步:收发信息发送信息:qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port) qint64 QUdpSocket::writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port)参数: data --》要发送的内容size --》打算发送多少字节的数据address --》对方的ip port --》对方的端口号接收信息:qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address = Q_NULLPTR, quint16 *port = Q_NULLPTR)参数:data --》保存接收的数据maxSize --》打算接收多少字节的数据注意:  如果对方有发送信息过来,不能直接调用readDatagram接收如果对方有发送信息过来,QUdpSocket的对象会自动触发readyRead(),程序员在自定义的槽函数里面调用readDatagram接收信息即可
第三步:关闭close()
2.1.1.1 示例代码:
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QUdpSocket>
#include <QHostAddress>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QUdpSocket *udpSocket;
};
#endif // WIDGET_H// widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 设置窗口标题this->setWindowTitle("发送端");// 创建udp套接字udpSocket = new QUdpSocket(this);// 绑定ip和端口号udpSocket->bind(QHostAddress("192.168.10.9"), 10000);
}Widget::~Widget()
{delete ui;
}// 发送消息
void Widget::on_pushButton_clicked()
{// 获取文本编辑框中输入的信息QString sendMsg = ui->textEdit->toPlainText();// 发送消息udpSocket->writeDatagram(sendMsg.toUtf8(), QHostAddress("192.168.10.9"), 20000);qDebug()<<"点击了发送消息";
}

2.1.2 接收端:

第一步:创建QUdpSocket套接字对象,调用bind绑定ip和端口号
第二步:收发信息发送信息:qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port) qint64 QUdpSocket::writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port)参数: data --》要发送的内容size --》打算发送多少字节的数据address --》对方的ip port --》对方的端口号接收信息:qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address = Q_NULLPTR, quint16 *port = Q_NULLPTR)参数:data --》保存接收的数据maxSize --》打算接收多少字节的数据注意:  如果对方有发送信息过来,不能直接调用readDatagram接收如果对方有发送信息过来,QUdpSocket的对象会自动触发readyRead(),程序员在自定义的槽函数里面调用readDatagram接收信息即可
第三步:关闭close()
2.1.2.1 示例代码
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QUdpSocket>
#include <QHostAddress>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void recvMsg();private:Ui::Widget *ui;QUdpSocket *udpRecvSocket;
};
#endif // WIDGET_H// widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 设置窗口标题this->setWindowTitle("接收端");// 创建udp套接字udpRecvSocket = new QUdpSocket(this);// 绑定ip和端口号udpRecvSocket->bind(QHostAddress("192.168.10.9"), 20000);// 主动关联readyRead()信号,在槽函数里面接收信息connect(udpRecvSocket, &QIODevice::readyRead, this, &Widget::recvMsg);
}Widget::~Widget()
{delete ui;
}void Widget::recvMsg()
{char recvBuf[100];udpRecvSocket->readDatagram(recvBuf,sizeof (recvBuf));//在文本浏览框中显示内容ui->textBrowser->append(recvBuf);qDebug()<<"接收消息槽函数";
}
2.1.2.2 现象:

在这里插入图片描述

2.2 bind需要注意的问题

linux中: INADDR_ANY --》获取本地主机上的任意一个ip
QT中: QHostAddress::Any --》获取本地主机上的任意一个ip
mysock.bind(QHostAddress::Any,20000,QAbstractSocket::ReuseAddressHint);
绑定任意一个ip地址,并且端口号可以复用

相关文章:

【QT】QT中的网络编程(TCP 和 UDP通信)

QT中的网络编程&#xff08;TCP 和 UDP通信&#xff09; 1.tcp1.1 tcp通信1.1.1 相比linux中tcp通信:1.1.2 QT中的tcp通信: 1.2 tcp通信流程1.2.1 服务器流程&#xff1a;1.2.1.1 示例代码1.2.1.2 现象 1.2.2 客户端流程&#xff1a;1.2.2.1 示例代码1.2.2.2 现象&#xff1a; …...

Spring MVC @RequestBody 注解怎么用?接收什么格式的数据?

RequestBody 注解的作用 RequestBody 将方法上的参数绑定到 HTTP 请求的 Body&#xff08;请求体&#xff09;的内容上。 当客户端发送一个包含数据的请求体&#xff08;通常在 POST, PUT, PATCH 请求中&#xff09;时&#xff0c;RequestBody 告诉 Spring MVC 读取这个请求体…...

第38课 常用快捷操作——双击“鼠标左键”进入Properties Panel

概述 在设计过程中&#xff0c;我们经常需要更改某个图元的属性&#xff0c;例如更该焊盘的大小、更改网络的名称等等。 在AD 20中&#xff0c;更改属性一般都是在Properties Panel上完成的。 当我们要更改某个图元的属性时&#xff0c;我们用鼠标左键双击它&#xff0c;就可…...

【git】获取特定分支和所有分支

1 特定分支 1.1 克隆指定分支&#xff08;默认只下载该分支&#xff09; git clone -b <分支名> --single-branch <仓库URL> 示例&#xff08;克隆 某一个 分支&#xff09;&#xff1a; git clone -b xxxxxx --single-branch xxxxxxx -b &#xff1a;指定分支…...

从零开发一个B站视频数据统计Chrome插件

从零开发一个B站视频数据统计Chrome插件 前言 B站&#xff08;哔哩哔哩&#xff09;作为国内最大的弹幕视频网站之一&#xff0c;视频的播放量、点赞、投币、收藏等数据对于内容创作者和数据分析者来说非常重要。本文将带你一步步实现一个Chrome插件&#xff0c;自动统计并展…...

经典算法 石子合并问题

石子合并问题 问题描述 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆&#xff0c;并将新的一堆的石子数&#xff0c;记为该次合并的得分。试设计出一个算法,计算出将N堆石子合并成1堆最大得分和最小得分。 输入描述…...

[stm32] 4-1 USART(1)

文章目录 前言4-2 USART与串口通信(1)USART简介什么是USART?USART名字的含义&#xff1f;如何使用USART&#xff1f; USART的工作原理什么是串并转换&#xff1f;为什么要进行串并转换&#xff1f;移位寄存器串并行转换电路 USART寄存器组和完整框图 前言 本笔记内容&#xff…...

智能家居的OneNet云平台

一、声明 该项目只需要创建一个产品&#xff0c;然后这个产品里面包含几个设备&#xff0c;而不是直接创建几个产品 注意&#xff1a;传输数据使用到了不同的power&#xff0c;还有一定要手机先联网才能使用云平台 二、OneNet云平台创建 &#xff08;1&#xff09;Temperatur…...

记录两个免费开源又好用的后台模版vue3

一.element-plus-admin 一套基于vue3、element-plus、typesScript、vite的后台集成方案 1.简介 vue-element-plus-admin 是一个基于 element-plus 免费开源的中后台模版。使用了最新的 Vue3&#xff0c;Vite&#xff0c;Typescript等主流技术开发&#xff0c;开箱即用的中后…...

【AI生产力工具】Windsurf,一款AI编程工具

Windsurf 是 Codeium 公司推出的一款 AI 编程助手,它是一款集成深度上下文感知、多模型协作和实时代码管理的综合开发环境(IDE)。 Windsurf 作为 AI 编程工具的核心价值在于 “上下文感知 + 多模型协作 + 自动化工作流”,其深度集成的智能体系统(如 Flows 和 Cascade)正…...

YOLOv11改进:利用RT-DETR主干网络PPHGNetV2助力轻量化目标检测

这里写自定义目录标题 YOLOv11改进&#xff1a;利用RT-DETR主干网络PPHGNetV2助力轻量化目标检测1. 介绍2. 引言3. 技术背景3.1 YOLOv11概述3.2 RT-DETR与PPHGNetV23.3 相关工作 4. 应用使用场景5. 详细代码实现5.1 环境准备5.2 PPHGNetV2主干网络实现5.3 YOLOv11与PPHGNetV2集…...

Android 端如何监控 ANR、Crash、OOM 等严重问题

在移动互联网时代,Android 应用已经成为我们生活中不可或缺的一部分。从社交聊天到在线购物,从娱乐消遣到办公学习,几乎每个人的手机里都装满了各式各样的应用。然而,作为开发者,咱们得面对一个残酷的现实:用户的耐心是有限的。如果一个应用频繁卡顿、闪退,甚至直接崩掉…...

Mybatisplus:一些常用功能

自动驼峰 mybatis-plus:configuration:# 开启驼峰命名规则&#xff0c;默认true开启map-underscore-to-camel-case: true# 控制台日志打印&#xff0c;便于查看SQLlog-impl: org.apache.ibatis.logging.stdout.StdOutImpl TableName 作用&#xff1a;表名注解&#xff0c;标识…...

oracle 批量查询每张表的数据量

在 Oracle 中批量查询每张表的数据量,可以通过以下两种方法实现。根据数据量大小和实时性要求选择适合的方案: 方法一:通过数据字典快速查询(推荐) 原理: 使用 USER_TABLES(当前用户的表)或 DBA_TABLES(所有表,需DBA权限)中的 NUM_ROWS 字段,该字段记录了表的行数…...

linux netlink实现用户态和内核态数据交互

1&#xff0c;内核态代码 #include <linux/module.h> #include <linux/netlink.h> #include <net/sock.h> #define NETLINK_TEST 31 struct sock *nl_sk NULL; static void nl_recv_msg(struct sk_buff *skb) { struct nlmsghdr *nlh; int pid; …...

java 洛谷题单【算法2-2】常见优化技巧

P1102 A-B 数对 解题思路 输入读取与初始化&#xff1a; 使用 Scanner 读取输入。n 表示数组的长度&#xff0c;c 表示目标差值。使用一个 HashMap 存储数组中每个数字及其出现的次数&#xff0c;方便快速查找。数组 a 用于存储输入的数字。 构建哈希映射&#xff1a; 遍历数…...

WebAPI项目从Newtonsoft.Json迁移到System.Text.Json踩坑备忘

1.控制器层方法返回类型不能为元组 控制器层方法返回类型为元组时&#xff0c;序列化结果为空。 因为元组没有属性只有field&#xff0c;除非使用IncludeFields参数专门指定&#xff0c;否则使用System.Text.Json进行序列化时不会序列化field var options new JsonSerializ…...

batch normalization和layer normalization区别

Normalization无非就是这样一个操作&#xff1a; 其中x是输入数据&#xff0c;维度为&#xff08;B&#xff0c;T&#xff0c;C&#xff09;&#xff0c;其中B是batchsize&#xff0c;T是序列长度&#xff0c;C是embedding维度&#xff1b;括号内是标准化操作&#xff0c;γ和…...

音视频开发成长之路与音视频知识总结

音视频开发曾经是一个富有挑战性和技术深度的领域。我来分享整理音视频开发的成长路径和知识体系&#xff1a; 音视频开发成长路线图 1. 基础阶段&#xff08;1-3个月&#xff09; 计算机基础&#xff1a;C/C、数据结构、操作系统音视频基础概念&#xff1a;采样率、比特率、…...

【多线程】七、POSIX信号量 环形队列的生产者消费者模型

文章目录 Ⅰ. 信号量一、POSIX 信号量的概念二、POSIX 信号量的类型区别三、POSIX 信号量与 SystemV 信号量的区别Ⅱ. 线程信号量基本原理一、为什么要引入信号量❓二、PV 操作三、POSIX 信号量的实现原理四、CAS操作介绍Ⅲ. POSIX未命名信号量接口一、初始化无名信号量二、销毁…...

JVM 一文详解

目录 JVM 简介 JVM 中的内存区域划分 1. 堆&#xff08;一个进程只有一份 ------ 线程共享&#xff09; 2. 栈&#xff08;一个进程可以有 N 份 ------ 线程私有&#xff09; Java 虚拟机栈&#xff1a; 本机方法栈&#xff1a; 3. 程序计数器&#xff08;一个线程可以…...

OCR身份证识别(正反面)_个人证照OCR识别_开放API接口使用指南

一、接口简介 在数字化时代&#xff0c;快速准确地提取身份证信息变得尤为重要。**万维易源提供的“身份证OCR识别”API接口&#xff0c;能够快速提取二代居民身份证正反面的所有字段信息&#xff0c;包括姓名、性别、民族、出生日期、住址、身份证号、签发机关、有效期限等。…...

《淘宝 API 数据湖构建:实时商品详情入湖 + Apache Kafka 流式处理指南》

随着电商行业的蓬勃发展&#xff0c;淘宝作为头部电商平台&#xff0c;积累了海量的商品数据。构建淘宝 API 数据湖&#xff0c;将实时商品详情数据纳入其中&#xff0c;并借助 Apache Kafka 进行流式处理&#xff0c;能够为企业提供强大的数据支撑&#xff0c;助力精准营销、市…...

基于ArduinoIDE的任意型号单片机 + GPS北斗BDS卫星定位

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言1.1 器件选择1.2 接线方案 二、驱动实现2.1 核心代码解析&#xff08;arduino/ESP32-S3&#xff09; 三、坐标解析代码四、典型问题排查总结 前言 北斗卫星导航…...

代码随想录算法训练营第60期第二十二天打卡

大家好&#xff01;我们今天来到了一个全新的章节&#xff0c;回溯算法&#xff0c;那究竟什么是回溯算法&#xff0c;我们应该如何理解回溯算法&#xff0c;以及回溯算法可以解决的题目&#xff0c;我们今天就来一探究竟。 第一部分 回溯算法理论基础 其实我可以告诉大家的是…...

自主机器人模拟系统

一、系统概述 本代码实现了一个基于Pygame的2D自主机器人模拟系统&#xff0c;具备以下核心功能&#xff1a; 双模式控制&#xff1a;支持手动控制&#xff08;WASD键&#xff09;和自动导航模式&#xff08;鼠标左键设定目标&#xff09; 智能路径规划&#xff1a;采用改进型…...

基于QT的仿QQ音乐播放器

一、项目介绍 该项目是基于QT开发的⾳乐播放软件&#xff0c;界面友好&#xff0c;功能丰富&#xff0c;主要功能如下&#xff1a; 窗口hand部分&#xff1a; 点击最小化按钮&#xff0c;窗口最小化 点击最大化按钮&#xff0c;窗口最大化 点击关闭按钮&#xff0c;程序退出 …...

腾讯研究院:《工业大模型应用报告》(文末附下载方式)

腾讯研究院发布的《工业大模型应用报告》是一份系统探讨大模型技术在工业领域落地实践的研究成果。该报告基于腾讯在人工智能、云计算及产业互联网的实践经验&#xff0c;结合国内外典型案例&#xff0c;深入分析了工业大模型的行业价值、关键技术、应用场景及未来趋势。报告指…...

C语言-指针(一)

目录 指针 内存 概念 指针变量 取地址操作符&#xff08;&&#xff09; 操作符“ * ” 指针变量的大小 注意 指针类型的意义 作用 void * 指针 const修饰指针变量 const放在*前 const放在*后 双重const修饰 指针的运算 1.指针 - 整数 2.指针 - 指针 3.指…...

【DeepMLF】具有可学习标记的多模态语言模型,用于情感分析中的深度融合

这是一篇我完全看不懂的论文,写的好晦涩,适合唬人,所以在方法部分我以大白话为主 abstract 在多模态情感分析(MSA)中,多模态融合已经得到了广泛的研究,但融合深度和多模态容量分配的作用还没有得到充分的研究。在这项工作中,我们将融合深度、可扩展性和专用多模容量作…...