QT中使用UDP通信
本例程已在单台机器和路由器下的多台机器上测试成功。
只支持文本发送,如果特殊的数据类型比如结构体、表格发送还得另定义编码与解析。
代码在文章末尾。点击跳转
发送端构建思路:
1、引入与UDP通信相关的库和功能;
2、头文件中声明通信相关的对象udpSocket和按键绑定函数等;
3、定义函数内容:
[3.1]按键绑定函数中为读取目标端口、目标IP与发送内容的功能;
[3.2]再用UdpSocket库的功能进行发送。
接收端构建思路:
[跳转到接收端]
1、引入与UDP通信相关的库和功能;
2、头文件中声明通信相关的对象udpSocket、按键绑定函数和接收处理函数等;
3、定义函数内容:
[3.1]读取端口号与IP地址,绑定端口,验证端口绑定成功;
[3.2]定义接收处理函数,与事件“接收到信号”进行绑定,每次接收到数据便执行此函数。
发送端
发送端的ui设计如下
其中,上方的PlainTextEdit组件是数据发送的输入框;下方的PlainTextEdit组件是信息输出框;
端口号输入框使用QSpinBox组件,IP输入框使用QLineEdit组件。
具体实现代码我会放在文末,[点击跳转]下面对关键部分代码做以下解释。
首先,UDP通信是QT安装时自带的,但是新建的QT工程并没有引入,需要在.pro工程文件中加入下面代码引入UDP通信功能:
QT += network
这样,在头文件中就可以包含与UDP通信相关的库了:
#include <QUdpSocket>
头文件内容如下:
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
QUdpSocket *udpSocket;//
QString getLocalIP();//获取本机IP地址
};
#endif // WIDGET_H
其中,有一个按键的绑定函数,一个QUdpSocket的指针对象,还有一个获取本机IP的函数。
构造函数如下,为udpSocket指针对象new一块空间:
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QString localIP=getLocalIP();//本机IP
this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);
udpSocket=new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
}
析构函数如下,断开udp通信以及手动删除new的对象:
Widget::~Widget()
{
udpSocket->abort();
delete udpSocket;
delete ui;
}
按键绑定函数的定义如下,可以根据自身需要修改:
void Widget::on_pushButton_clicked()
{
QString targetIP=ui->lineEdit->text();
QHostAddress targetAddr(targetIP); //目标IP
quint16 targetPort = ui->spinBox->value(); //目标端口号
QString msg = ui->plainTextEdit->toPlainText(); //发送内容
QByteArray str = msg.toUtf8();
udpSocket->writeDatagram(str, targetAddr, targetPort); //发送函数
ui->window->appendPlainText("[send]" + msg); //信息栏显示
ui->plainTextEdit->clear();
ui->plainTextEdit->setFocus();
}
获取本机IP函数:
QString Widget::getLocalIP()
{
QString hostName=QHostInfo::localHostName();//本地主机名
QHostInfo hostInfo=QHostInfo::fromName(hostName);
QString localIP="";
QList<QHostAddress> addList=hostInfo.addresses();//
if (!addList.isEmpty())
for (int i=0;i<addList.count();i++)
{
QHostAddress aHost=addList.at(i);
if (QAbstractSocket::IPv4Protocol==aHost.protocol())
{
localIP=aHost.toString();
break;
}
}
return localIP;
}
接收端
接收端ui设计如下:
其中,目标端口使用的是QSpinBox组件,目标IP使用的是QLineEdit组件,接受框用PlainTextEdit组件。
同样在.pro文件中加入network模块
QT += network
头文件内容加入:
#include <QUdpSocket>
头文件内容如下
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
QUdpSocket *udpSocket;//
QString getLocalIP();//获取本机IP地址
private slots:
void onSocketReadyRead();//读取socket传入的数据
void on_pushButton_clicked();
};
#endif // WIDGET_H
与发送端的构成类似,信号函数多了一个读取socket传入的数据函数:void onSocketReadyRead()
各个函数的定义如下:
构造函数如下
由于接收端需要适时监听端口号收到的信息,因此需要将readyRead()信号与自定义的信号读取函数onSocketReadyRead()关联。
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QString localIP=getLocalIP();//本机IP
this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);
udpSocket=new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
connect(udpSocket,SIGNAL(readyRead()),
this,SLOT(onSocketReadyRead()));
// udpSocket=new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
// connect(udpSocket,SIGNAL(readyRead()),
// this,SLOT(onSocketReadyRead()));
}
析构函数如下
Widget::~Widget()
{
udpSocket->abort();
delete udpSocket;
delete ui;
}
要监听端口来接受信息,首先要对端口号进行绑定,当udpSocket->bind(port)返回true时表示端口绑定成功
void Widget::on_pushButton_clicked()
{
quint16 port = ui->spinBox->value(); //本机UDP端口
if (udpSocket->bind(port)) //绑定端口成功
{
ui->plainTextEdit->appendPlainText("**成功绑定端口");
ui->plainTextEdit->appendPlainText("**绑定端口:" +
QString::number(udpSocket->localPort())); }
}
socket读取函数如下,当端口监听到有数据发来,就会执行此函数
void Widget::onSocketReadyRead()
{
while(udpSocket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize()); //数据格式统一
QHostAddress peerAddr;
quint16 peerPort;
udpSocket->readDatagram(datagram.data(),
datagram.size(),&peerAddr,&peerPort); //接收数据
QString str=datagram.data(); //数据转换为QT的ui界面使用的QString类型
QString peer="[From "+peerAddr.toString()+":"
+QString::number(peerPort)+"] ";
ui->plainTextEdit->appendPlainText(peer+str);
}
}
获取ip函数与发送端相同
QString Widget::getLocalIP()
{
QString hostName=QHostInfo::localHostName();//本地主机名
QHostInfo hostInfo=QHostInfo::fromName(hostName);
QString localIP="";
QList<QHostAddress> addList=hostInfo.addresses();//
if (!addList.isEmpty())
for (int i=0;i<addList.count();i++)
{
QHostAddress aHost=addList.at(i);
if (QAbstractSocket::IPv4Protocol==aHost.protocol())
{
localIP=aHost.toString();
break;
}
}
return localIP;
}
演示
IP查询可以cmd到终端输入ipconfig查询。
端口号绑定不成功的话换一个数字重试,可能与计算机已经占用的端口发生了冲突,一般选择时尽量选择大一些的端口号避免冲突。
不要开串口调试工具同时进行调试,使用时应该断开串口调试共苦,原因就是上一点的串口冲突问题。
单机测试使用时,开两个QT应用,发送和接收程序都运行,先根据自己电脑的IP地址设置号IP,端口号保持一致。在接收端点击绑定端口,端口绑定成功后会有提示,再到发送端发送自己像发送的内容,图片中发送的Hello已经成功接收到。
多机使用时,保证IP处于同一网段,接收端和发送端端口设置一致,IP使用接收端电脑的IP地址。
代码地址:
❤️跳转过来啦❤️
百度云
链接:https://pan.baidu.com/s/1VrwGKHWd2RRv_PNu7tUZvg
提取码:pkci
Github
https://github.com/FLBa9762/Qt-UdpSocket-Code.git