核心代码
1. 绑定端口
要接收UDP数据报,必须绑定一个端口,来监听数据传入。
//绑定端口
void bindPort()
{
quint16 port = ui->spinBindPort->value(); // 本机UDP端口
if (udpSocket->bind(port)) // 绑定端口成功
{
ui->plainTextEdit->appendPlainText("**已成功绑定");
ui->plainTextEdit->appendPlainText("**绑定端口:" + QString::number(udpSocket->localPort()));
ui->actStart->setEnabled(false);
ui->actStop->setEnabled(true);
}
else
ui->plainTextEdit->appendPlainText("**绑定失败");
}
2. 解绑端口
//解除绑定
void unbind()
{
udpSocket->abort(); // 解除绑定
ui->actStart->setEnabled(true);
ui->actStop->setEnabled(false);
ui->plainTextEdit->appendPlainText("**已解除绑定");
}
3. 发送数据
单播和广播发送消息都使用writeDatagram()函数,区别是单播向一个目标发送数据时需要指定目标IP和端口,广播时只需要将目标地址更换为一个特殊的地址,即广播地址QHostAddress::Broadcast。
// 发送消息 按钮
void MainWindow::on_btnSend_clicked()
{
QString targetIP = ui->comboTargetIP->currentText(); //目标IP
QHostAddress targetAddr(targetIP);
quint16 targetPort = ui->spinTargetPort->value();//目标port
QString msg = ui->editMsg->text();//发送的消息内容
QByteArray str = msg.toUtf8();
udpSocket->writeDatagram(str,targetAddr,targetPort); //发出数据报
ui->plainTextEdit->appendPlainText("[out] "+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
}
// 广播消息 按钮
void MainWindow::on_btnBroadcast_clicked()
{
quint16 targetPort=ui->spinTargetPort->value(); //目标端口
QString msg=ui->editMsg->text();
QByteArray str=msg.toUtf8();
udpSocket->writeDatagram(str,QHostAddress::Broadcast,targetPort);
ui->plainTextEdit->appendPlainText("[broadcast] "+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
}
4. 接收数据
QUdpSocket接收到数据报后发射readyRead()信号,可以实现槽函数来读取缓冲区的数据。
// 读取收到的数据报
void MainWindow::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();
QString peer="[From "+peerAddr.toString()+":"+QString::number(peerPort)+"] ";
ui->plainTextEdit->appendPlainText(peer+str);
}
}
注意:qint64 readDatagram(char *data, qint64 maxSize, QHostAddress *address = Q_NULLPTR, quint16 *port = Q_NULLPTR) 函数中data和maxSize是必须的,maxSize指定最多读取多少字节数据到data中,address和port是可选的,可以获取数据包来源的IP地址和端口。示例中传输字符串,不需要做特殊处理,如果是自定义的其他格式,就需要对接收到的数据另做解析。
5. 程序流程
单播:若两个程序在同一台设备运行,程序A绑定端口1000,程序B绑定端口2000,那么想要互相发送消息,就需要将对方的IP地址和端口设置为目标IP和端口。 若两个程序在不同设备运行,那么两个程序可以绑定相同的端口,此时IP地址不同了,不会导致绑定冲突。一般的UDP程序都是在不同设备上运行,约定一个固定端口作为通信端口。 广播:发送者向指定端口发送数据,不在乎IP地址。所有在同一网络范围的绑定了指定端口的UDP客户端都能收到数据。
|