【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地址,并且端口号可以复用

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

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

相关文章

架构思维:使用懒加载架构实现高性能读服务

文章目录 一、引言二、读服务的功能性需求三、两大基本设计原则1. 架构尽量不要分层2. 代码尽可能简单 四、实战方案&#xff1a;懒加载架构及其四大挑战五、改进思路六、总结与思考题 一、引言 在任何后台系统设计中&#xff0c;「读多写少」的业务场景占据主流&#xff1a;浏…

永磁同步电机控制算法--基于PI的位置伺服控制

一、原理介绍 永磁同步伺服系统是包含了电流环、速度环和位置环的三环控制系统。 伺服系统通过电流检测电路和光电编码器检测电动机三相绕组电流和转子位置θ&#xff0c;通过坐标变换&#xff0c;计算出转矩电流分量iq和励磁电流分量id。 位置信号指令与实际转子位置信号的差…

linux系统线程实现原理浅析

背景 对进程和线程的理解&#xff0c;之前一直都是凭一些零碎不完整的信息在理解&#xff1b; linux的进程和线程基本上一样&#xff0c;线程是轻量级进程&#xff0c;彼此有关联又独立。 得亏内核支持的好&#xff0c;写用户态程序可以不依赖于实现的理解&#xff0c;只需要…

MySQL连接报错处理:1130-host ... is not allowed to connect to this MySql server

在MySQL安装完成后&#xff0c;很多开发者会遇到这样一个问题&#xff1a; 错误代码 1130&#xff1a;host xxx.xxx.xxx.xxx is not allowed to connect to this MySql server 这个错误通常出现在你尝试通过远程工具&#xff08;如 Navicat、DBeaver 等&#xff09;连接 MySQL …

Linux系统之----进程控制

1.进程创建 进程创建部分由于就是fork函数&#xff0c;还有写时拷贝&#xff0c;在上一篇已经讲述过了&#xff0c;这里不在进行赘述&#xff0c;有疑问的读者可以前往上一篇博文《Linux系统--程序地址空间》中阅读&#xff01; 这里在多说一嘴写时拷贝吧 我们可以对比一下写…

Spring框架的设计目标,设计理念,和核心是什么 ?

Spring框架是一个为简化企业级应用开发而设计的开源框架&#xff0c;它提供了全面的基础设施支持&#xff0c;使得Java应用开发更加简单、快速和可维护。下面我将详细解释Spring框架的设计目标、设计理念以及核心组件。 设计目标 简化Java企业级应用开发&#xff1a;通过提供…

Red Hat6.4环境下搭建DNS服务器

DNS服务器&#xff08;Domain Name System Server&#xff09;是互联网中用于将域名&#xff08;如 www.example.com&#xff09;解析为IP地址&#xff08;如 192.0.2.1&#xff09;的服务器。它是互联网基础设施的重要组成部分&#xff0c;帮助用户通过易于记忆的域名访问网站…

Nginx核心功能 02

目录 Nginx代理技术核心概念 &#xff08;一&#xff09;正向代理&#xff08;Forward Proxy&#xff09; 1. 基本定义 2. 技术原理 3. 应用场景 &#xff08;二&#xff09;反向代理&#xff08;Reverse Proxy&#xff09; 1. 基本定义 2. 技术原理 3. 应用场景 一、…

关于Python:3. Python标准库和常用模块

1. os 和 sys&#xff08;系统编程基础&#xff09; 这两个模块是进行系统层面操作&#xff08;如文件管理、路径处理、环境变量访问等&#xff09;必不可少的工具。 os 模块 os 主要是用于与操作系统交互的&#xff0c;比如&#xff1a; 文件和目录操作 获取系统信息 运行…

Java基于SaaS模式多租户ERP系统源码

目录 一、系统概述 二、开发环境 三、系统功能介绍 一、系统概述 ERP&#xff0c;全称 Enterprise Resource Planning 即企业资源计划。是一种集成化的管理软件系统&#xff0c;它通过信息技术手段&#xff0c;将企业的各个业务流程和资源管理进行整合&#xff0c;以提高企业…

个人健康中枢的多元化AI网络革新与精准健康路径探析

引言 随着数字化转型的深入推进,个人健康中枢作为集成化健康管理系统,正在从传统的单一功能向多元化的AI驱动方向快速发展。在这一背景下,新兴网络硬件技术,特别是DPU(数据处理单元)和全光网络的出现,为个人健康中枢的革新提供了前所未有的机遇。本研究将深入探讨这些技…

AI跑得快,MCP来加速——模型计算平台在训练与推理中的硬核作用

AI跑得快,MCP来加速——模型计算平台在训练与推理中的硬核作用 一、引言:AI是“铁人三项”,但训练+推理常常“掉链子” 如今的人工智能系统越来越强,像ChatGPT、Stable Diffusion、Segment Anything等模型不断刷新技术天花板。但你是否也注意到: 明明模型设计得挺好,训练…

《MATLAB实战训练营:从入门到工业级应用》工程实用篇-自动驾驶初体验:车道线检测算法实战(MATLAB2016b版)

《MATLAB实战训练营&#xff1a;从入门到工业级应用》工程实用篇-&#x1f697; 自动驾驶初体验&#xff1a;车道线检测算法实战&#xff08;MATLAB2016b版&#xff09; 大家好&#xff01;今天我要带大家一起探索自动驾驶中一个非常基础但又至关重要的技术——车道线检测。我…

模型部署——cuda编程入门

CUDA中的线程与线程束 kernel是在device上线程中并行执行的函数&#xff0c;核函数用__global__符号声明&#xff0c;在调用时需要用<<<grid_size, block_size>>>来指定kernel要执行的线程数量。在CUDA中&#xff0c;每一个线程都要执行核函数&#xff0c;并…

WordPress不支持中文TAG标签出现404的解决方法

我们在后台编辑文章时输入中文标签会发现出现404的情况&#xff0c;其实中文TAG标签链接无法打开的原因是WordPress不支持中文的编码。那么解决的方法也很容易&#xff0c;只要改代码让WordPress能支持中文的编码形式&#xff0c;也就是UTF-8和GBK编码即可&#xff0c;无需用到…

金融信贷公司所需的技术和风控体系及其带来的价值

金融信贷公司的技术架构通过集成传统大型机系统与现代数据平台&#xff0c;能够有效支持金融信贷业务的运作&#xff0c;同时通过大数据、ETL、报表开发、数据仓库等技术为公司带来更高效的数据驱动决策、精准的风控分析和更灵活的业务支持。 一、公司技术架构 数据仓库架构&…

《AI大模型应知应会100篇》第43篇:大模型幻觉问题的识别与缓解方法

第43篇&#xff1a;大模型幻觉问题的识别与缓解方法 摘要 当AI系统自信满满地编造"量子计算机使用香蕉皮作为能源"这类荒谬结论时&#xff0c;我们不得不正视大模型的幻觉问题。本文通过15个真实案例解析、6种检测算法实现和3套工业级解决方案&#xff0c;带您掌握…

计算方法实验五 插值多项式的求法

【实验性质】 综合性验 【实验目的】 掌握Lagrange插值算法、Newton插值算法&#xff1b;理解Newton插值算法相对于Lagrange插值算法的优点。 【实验内容】 先用C语言自带的系统函数sin x求出 的值&#xff0c;然后分别用Lagrange、Newton方法求出的值&#xff0c;并与用…

文献总结:TPAMI端到端自动驾驶综述——End-to-End Autonomous Driving: Challenges and Frontiers

端到端自动驾驶综述 1. 文章基本信息2. 背景介绍3. 端到端自动驾驶主要使用方法3. 1 模仿学习3.2 强化学习 4. 测试基准4.1 真实世界评估4.2 在线/闭环仿真测试4.3 离线/开环测试评价 5. 端到端自动驾驶面临的挑战5.1 多模态输入5.2 对视觉表征的依赖5.3 基于模型的强化学习的世…

PostgreSQL:pgAdmin 4 使用教程

pgAdmin 4 是一个用于管理和维护 PostgreSQL 数据库的强大工具。它提供了一个图形化界面&#xff0c;使用户能够轻松地连接到数据库、创建表、运行 SQL 语句以及执行其他数据库管理任务。 安装和使用 安装 pgAdmin 4 安装 pgAdmin 4 非常简单。下载并运行安装程序&#xff0…