发送和接收UDP数据报

QUdpSocket类可以用来发送和接收UDP数据报(datagram)。UDP是一种不可靠的,面向数据报的协议。一些应用层的协议使用UDP,因为它比TCP更加小巧轻便。采用UDP,数据是以包(数据报)的形式从一个主机发送到另一个主机的。这里并没有连接的概念,而且如果UDP包没有被成功投递,它不会向发送者报告任何错误。

我们将会通过Weather Balloon和Weather Station 这两个实例来看看在Qt应用程序中是如何使用UDP的。Weather Balloon应用程序模拟气象气球的功能,每2秒钟就发送个包含当前天气情况的UDP数据报(假设使用无线连接)。

class WeatherBalloon : public QPushButton
{Q_OBJECTpublic:WeatherBalloon(QWidget *parent = 0);double temperature() const;double humidity() const;double altitude() const;private slots:void sendDatagram();private:QUdpSocket udpSocket;QTimer timer;
};

WeatherBalloon类派生自QPushButton。它借助QPushButton的QUdpSocket私有变量与WeatherStation进行通信。

WeatherBalloon::WeatherBalloon(QWidget *parent): QPushButton(tr("Quit"), parent)
{connect(this, SIGNAL(clicked()), this, SLOT(close()));connect(&timer, SIGNAL(timeout()), this, SLOT(sendDatagram()));timer.start(2 * 1000);setWindowTitle(tr("Weather Balloon"));
}

在构造函数中,利用一个QTimer来实现每2秒钟调用一次sendDatagram()。

void WeatherBalloon::sendDatagram()
{QByteArray datagram;QDataStream out(&datagram, QIODevice::WriteOnly);out.setVersion(QDataStream::Qt_4_3);out << QDateTime::currentDateTime() << temperature() << humidity()<< altitude();udpSocket.writeDatagram(datagram, QHostAddress::LocalHost, 5824);
}

在sendDatagram()中,生成并发送一个包含当前日期、时间、温度、湿度和高度的数据报:

这个数据报是利用QUdpSocket::writeDatagram()发送的。writeDatagram()的第二个和第三个参数是IP 地址和另一端的端口号(Weather Station)。 对于这个实例,我们假设Weather Station 和Weather Balloon 运行在同一台机器上,所以使用127.0.0.1(QHostAddress::LocalHost)的IP地址,它是指定本地主机的特殊地址。

与QTcpSocket::connectToHost()不同,QUdpSocket::writeDatagram()不接受主机名称,而只能使用主机地址。如果想在这里把主机名称解析成为它的IP地址,有两种选择:在查找发生时阻塞,然后使用QHostnfo::fromNamne()静态函数;或者,使用QHostUnfo::lookupHost()静态函数。当查找完成时,它将立即返回,同时利用含有相应地址的:QHostInfo对象传递而调用槽。

int main(int argc, char *argv[])
{QApplication app(argc, argv);WeatherBalloon balloon;balloon.show();return app.exec();
}

main()函数仅仅创建了一个WeatherBalloon对象,它既作为一个UDP端进行服务,也作为一个QPushButton显示在屏幕上。单击QPushButton,就可以退出应用程序。现在看一下WeatherStation客户端的源代码:

weatherballon.h

#ifndef WEATHERBALLOON_H
#define WEATHERBALLOON_H#include <QPushButton>
#include <QTimer>
#include <QUdpSocket>class WeatherBalloon : public QPushButton
{Q_OBJECTpublic:WeatherBalloon(QWidget *parent = 0);double temperature() const;double humidity() const;double altitude() const;private slots:void sendDatagram();private:QUdpSocket udpSocket;QTimer timer;
};#endif

weatherballon.cpp

#include <QtCore>
#include <QtNetwork>
#include <cstdlib>#include "weatherballoon.h"WeatherBalloon::WeatherBalloon(QWidget *parent): QPushButton(tr("Quit"), parent)
{connect(this, SIGNAL(clicked()), this, SLOT(close()));connect(&timer, SIGNAL(timeout()), this, SLOT(sendDatagram()));timer.start(2 * 1000);setWindowTitle(tr("Weather Balloon"));
}double WeatherBalloon::temperature() const
{return -20.0 + (2.0 * std::rand() / (RAND_MAX + 1.0));
}double WeatherBalloon::humidity() const
{return 20.0 + (2.0 * std::rand() / (RAND_MAX + 1.0));
}double WeatherBalloon::altitude() const
{return 7000 + (100.0 * std::rand() / (RAND_MAX + 1.0));
}void WeatherBalloon::sendDatagram()
{QByteArray datagram;QDataStream out(&datagram, QIODevice::WriteOnly);out.setVersion(QDataStream::Qt_4_3);out << QDateTime::currentDateTime() << temperature() << humidity()<< altitude();udpSocket.writeDatagram(datagram, QHostAddress::LocalHost, 5824);
}

main.cpp

#include <QApplication>#include "weatherballoon.h"int main(int argc, char *argv[])
{QApplication app(argc, argv);WeatherBalloon balloon;balloon.show();return app.exec();
}


现在看一下Weather Station客户端的源代码:

class WeatherStation : public QDialog
{Q_OBJECTpublic:WeatherStation(QWidget *parent = 0);private slots:void processPendingDatagrams();private:QUdpSocket udpSocket;QLabel *dateLabel;QLabel *timeLabel;QLabel *temperatureLabel;QLabel *humidityLabel;QLabel *altitudeLabel;QLineEdit *dateLineEdit;QLineEdit *timeLineEdit;QLineEdit *temperatureLineEdit;QLineEdit *humidityLineEdit;QLineEdit *altitudeLineEdit;
};

WeatherStation类派生自QDialog。它监听一个特定的UDP端口,解析任何到来的数据报(来自于Weather Balloon),并且把它们的内容显示到5个只读的QLineEdit中。这里唯一需要注意的私有变量是QUdpSocket类型的udpSocket,我们将利用它来接收数据报。

WeatherStation::WeatherStation(QWidget *parent): QDialog(parent)
{udpSocket.bind(5824);connect(&udpSocket, SIGNAL(readyRead()),this, SLOT(processPendingDatagrams()));...
}

在构造函数中,首先把QUdpSocket绑定到WeatherBalloon所传送的端口。因为我们没有指定主机地址,套接字将在运行Weather Station的机器上接收发往任意IP地址的数据报。然后,将套接字的readyRead()信号与提取和显示数据的processPendingDatagrams()私有槽连接起来。

void WeatherStation::processPendingDatagrams()
{QByteArray datagram;do {datagram.resize(udpSocket.pendingDatagramSize());udpSocket.readDatagram(datagram.data(), datagram.size());} while (udpSocket.hasPendingDatagrams());QDateTime dateTime;double temperature;double humidity;double altitude;QDataStream in(&datagram, QIODevice::ReadOnly);in.setVersion(QDataStream::Qt_4_3);in >> dateTime >> temperature >> humidity >> altitude;dateLineEdit->setText(dateTime.date().toString());timeLineEdit->setText(dateTime.time().toString());temperatureLineEdit->setText(tr("%1 C").arg(temperature));humidityLineEdit->setText(tr("%1%").arg(humidity));altitudeLineEdit->setText(tr("%1 m").arg(altitude));
}

当接收到数据报时,就调用processPendingDatagrams()槽。QUdpSocket 将收到的数据报进行排队并让我们可以一次一个地读取它们。通常情况下,应该只有一个数据报,但是不能排除在发射readyRead()信号前发送端连续发送一些数据报的可能性。如果那样的话,可以忽略除最后一个以外的其他所有数据报,因为之前的数据报包含的只是过期的天气情况。

pendingDatagramSize()函数返回第一个待处理的数据报的大小。从应用程序的角度来看,数据报总是作为一个单一的数据单元来发送和接收的。这意味着只要有任意字节的数据可用,就认为整个数据报都可以被读取。readDatagram()调用把第一个待处理的数据报的内容复制到指定的char*缓冲区中(如果缓冲区空间太小,就直接截断数据),并且前移至下一个待处理的数据报。一旦读取了所有的数据报,就把最后一个数据报(包含最新气象状况测量值的数据报)分解为几个部分,并且用新的数据来组装QLineEdit。

int main(int argc, char *argv[])
{QApplication app(argc, argv);WeatherStation station;station.show();return app.exec();
}

最后,在main()中,我们创建并显示WeatherStation。

至此就完成了UDP发送端和接收端的代码。这个应用程序已经尽可能地简单了,它只是由Weather Balloon发送数据报,由Weather Station接收它们。在绝大多数实际应用中,这两个应用程序都需要通过它们的套接字读取和写入。QUdpSocket::writeDatagram()函数可以传递主机地址和端
口号,所以QUdpSocket可以从用bind()绑定的主机和端口读取数据,并且将其写入到其他的主机和端口。

weatherstation.h

#ifndef WEATHERSTATION_H
#define WEATHERSTATION_H#include <QDialog>
#include <QUdpSocket>class QLabel;
class QLineEdit;class WeatherStation : public QDialog
{Q_OBJECTpublic:WeatherStation(QWidget *parent = 0);private slots:void processPendingDatagrams();private:QUdpSocket udpSocket;QLabel *dateLabel;QLabel *timeLabel;QLabel *temperatureLabel;QLabel *humidityLabel;QLabel *altitudeLabel;QLineEdit *dateLineEdit;QLineEdit *timeLineEdit;QLineEdit *temperatureLineEdit;QLineEdit *humidityLineEdit;QLineEdit *altitudeLineEdit;
};#endif

weatherstation.cpp

#include <QtGui>
#include <QtNetwork>#include "weatherstation.h"WeatherStation::WeatherStation(QWidget *parent): QDialog(parent)
{udpSocket.bind(5824);connect(&udpSocket, SIGNAL(readyRead()),this, SLOT(processPendingDatagrams()));dateLabel = new QLabel(tr("Date:"));timeLabel = new QLabel(tr("Time:"));temperatureLabel = new QLabel(tr("Temperature:"));humidityLabel = new QLabel(tr("Humidity:"));altitudeLabel = new QLabel(tr("Altitude:"));dateLineEdit = new QLineEdit;timeLineEdit = new QLineEdit;temperatureLineEdit = new QLineEdit;humidityLineEdit = new QLineEdit;altitudeLineEdit = new QLineEdit;dateLineEdit->setReadOnly(true);timeLineEdit->setReadOnly(true);temperatureLineEdit->setReadOnly(true);humidityLineEdit->setReadOnly(true);altitudeLineEdit->setReadOnly(true);QGridLayout *mainLayout = new QGridLayout;mainLayout->addWidget(dateLabel, 0, 0);mainLayout->addWidget(dateLineEdit, 0, 1);mainLayout->addWidget(timeLabel, 1, 0);mainLayout->addWidget(timeLineEdit, 1, 1);mainLayout->addWidget(temperatureLabel, 2, 0);mainLayout->addWidget(temperatureLineEdit, 2, 1);mainLayout->addWidget(humidityLabel, 3, 0);mainLayout->addWidget(humidityLineEdit, 3, 1);mainLayout->addWidget(altitudeLabel, 4, 0);mainLayout->addWidget(altitudeLineEdit, 4, 1);setLayout(mainLayout);setWindowTitle(tr("Weather Station"));
}void WeatherStation::processPendingDatagrams()
{QByteArray datagram;do {datagram.resize(udpSocket.pendingDatagramSize());udpSocket.readDatagram(datagram.data(), datagram.size());} while (udpSocket.hasPendingDatagrams());QDateTime dateTime;double temperature;double humidity;double altitude;QDataStream in(&datagram, QIODevice::ReadOnly);in.setVersion(QDataStream::Qt_4_3);in >> dateTime >> temperature >> humidity >> altitude;dateLineEdit->setText(dateTime.date().toString());timeLineEdit->setText(dateTime.time().toString());temperatureLineEdit->setText(tr("%1 C").arg(temperature));humidityLineEdit->setText(tr("%1%").arg(humidity));altitudeLineEdit->setText(tr("%1 m").arg(altitude));
}

main.cpp

#include <QApplication>#include "weatherstation.h"int main(int argc, char *argv[])
{QApplication app(argc, argv);WeatherStation station;station.show();return app.exec();
}

Qt4_发送和接收UDP数据报相关推荐

  1. Qt 如何发送和接收UDP数据报

    在Qt4中,提供了QUdpSocket类,由于udp不像tcp,没有连接的概念,所以就没有QUdpServer,监听也是用同一个类,用法如下 #include <QUdpSocket>in ...

  2. 如何在Linux命令行下发送和接收UDP数据包

    众所周知,在传输层有两个常用的协议 TCP 和 UDP,本文介绍在 Linux 命令行下,如何使用 nc 命令发送或接收 UDP 数据包,这些命令的用法对调试 UDP 通信程序将有所帮助. 1. 问题 ...

  3. 网络编程【UDP数据报套接字编程】

    目录 1.网络编程基础 1.1 为什么需要网络编程? 1.2 什么是网络编程 1.3 网络编程中的基本概念 2.Socket套接字 2.1 分类 3.UDP数据报套接字编程 3.1 DatagramS ...

  4. 【网络编程】Socket套接字;UDP数据报套接字编程;TCP流套接字编程

    文章目录 1. 什么是网络编程 2. 网络编程中的基本概念 3. Socket套接字 4 UDP数据报套接字编程 4.1 客户端服务器交互流程 4.2 UDP版本的回显服务 4.3 英译汉服务 5. ...

  5. 分析udp数据报_深入的理解UDP编程

    什么是UDP? UDP是User Datagram Protocol(用户数据报协议)的缩写,它是一个简单的协议,简单到UDP规范RFC0768只有区区3页. UDP是工作在IP层之上的传输层协议,U ...

  6. 使用DatagramSocket发送、接收数据(Socket之UDP套接字)

    2019独角兽企业重金招聘Python工程师标准>>> 创建一个DatagramSocket实例,并将该对象绑定到指定IP地址.指定端口. 通过上面三个构造器中的任意一个构造器即可创 ...

  7. 分析udp数据报_Linux内核网络udp数据包发送(二)——UDP协议层分析

    1. 前言 本文分享了Linux内核网络数据包发送在UDP协议层的处理,主要分析了udp_sendmsg和udp_send_skb函数,并分享了UDP层的数据统计和监控以及socket发送队列大小的调 ...

  8. socket简介和udp网络程序-发送、接收数据

    socket简介 不同电脑上的进程之间如何通信 首要解决的问题是如何唯一标识一个进程,否则通信无从谈起! 在1台电脑上可以通过进程号(PID)来唯一标识一个进程,但是在网络中这是行不通的. 其实TCP ...

  9. 25. Python语言 Web 开发 之 Socket 编程 · 第一章 UDP发送与接收数据

    UDP发送与接收数据 本章主题 关键词 前导: 计算机网络的发展及基础网络概念 两台电脑的通信 IP地址介绍及分类 IP地址与IP协议 Windows 和 Linux 查看网卡信息 IP地址分类 以太 ...

最新文章

  1. 递归函数反向显示单链表
  2. BOOST_VMD_GET_TYPE宏相关的测试程序
  3. 弃用官方网站!Python 将所有 Bug 迁移到 GitHub 中
  4. 可搜索的文件? 是的你可以。 选择AsciiDoc的另一个原因
  5. 城市路(信息学奥赛一本通-T1381)
  6. (转)Android IPC机制详解
  7. php易错,PHP学习1:几种常见数据类型及其易错点
  8. linux 命令笔记
  9. 邻居把偶然的救急当成了依赖,怎么办?
  10. 关于身份证OCR识别,你知道多少?
  11. 【转载】RPG或SLG游戏在线地图编辑器
  12. 易语言获取硬盘特征字序列号加密特征字
  13. SpringBoot2.X 单元测试(Junit4.X) 基本配置
  14. [libtorrent] tracker 逻辑及源码解析(调试)
  15. 10.计算机基础之程序设计基础
  16. POI 导出 Excel:字体颜色、行列自适应、锁住、合并单元格、一文搞定……
  17. 别跑!JAVA!-----------一篇关于JAVA的博客
  18. SLAE — SecurityTube Linux组装考试
  19. 数字化教学资源平台html,数字化教学资源
  20. 键盘上的按键--键码 对应表

热门文章

  1. Alibaba之MySQL宝典_Alibaba之MySQL宝典流出!极致经典,堪称行业天花板
  2. 引物设计软件primer_常用生物学软件的安装与应用(三)—Primer6
  3. 实现一个闹钟_iPhone 闹钟停止时,如何自动播放你喜欢的音乐
  4. lua协程 unity_unity协程coroutine浅析
  5. 开发黑名单功能demo_突然让你开发Electron应用-electron特性练习操场-所见即所得的electron...
  6. 填坑黑苹果(VMware装MacOS) - 修改 Unlocker 补丁源码版
  7. ubuntu 14.04下练习lua
  8. 多个模块使用python logging
  9. css按钮口诀 - CSS BUG顺口溜
  10. Python学习笔记三(文件操作、函数)