从零开发B/S机架应用程序(三)-UDP

来源:互联网 发布:网站80端口开放攻击 编辑:程序博客网 时间:2024/06/06 12:30

网络通信

Qt 网络之UDP

UDP是一个轻量级的,不可靠的,面向数据报的无连接协议 。
我们现在几乎每个人都使用的腾讯QQ,其聊天时就是使用UDP协议进行消息发送的 。就像QQ那样,当有很多用户,发送的大部分都是短消息,要求能及时响应,并且对安全性要求不是很高的情况下使用UDP协议。

UDP通信客户端与服务器端的区别

通常来讲,客户端是不需要绑定端口号的,而服务器端是需要绑定监听的端口号。其
从socket通信的角度来看,UDP通信属于帧传输,TCP则是流传输,在帧传输过程中对于消息的次序和到达情况没有需求,所以UDP属于不可靠传输,不需要确认和排序。这样在客户端和服务器端的实现上就没有太大的差别了。

我们经常使用“ping”命令来测试两台主机之间TCP/IP通信是否正常,其实“ping”命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是通的。

UDP协议没有连接的过程,所以它的通信效果高;但也正因为如此,它的可靠性不如TCP协议高。

枚举 QHostAddress

QHostAddress::Null         //空地址对象,相当于QHostAddress()。QHostAddress::LocalHost     //IPv4本地主机地址,相当于QHostAddress(“127.0.0.1”)。QHostAddress::LocalHostIPv6 //IPv6本地主机地址,相当于 QHostAddress(“::1”)。QHostAddress::Broadcast  //Pv4广播地址,相当于QHostAddress(“255.255.255.255”)。QHostAddress::AnyIPv4   //IPv4 any-address,相当于QHostAddress(“0.0.0.0”)。与该地址绑定的socket将只监听IPv4接口。QHostAddress::AnyIPv6   //IPv6 any-address,相当于QHostAddress(“::”)。与该地址绑定的socket将只监听IPv4接口。QHostAddress::Any       //双any-address栈,与该地址绑定的socket将侦听IPv4和IPv6接口。

QByteArray

QByteArray类提供了字节数组,包含于QByteArray头文件中
QByteArray可以存储raw bytes和传统的8-bits的字符串,都是以’\0’结尾

QDataStream

Qt提供了非常方便的写文件操作QDataStream,可以使用流式操作来对数据进行读写
QDataStream是数据流,相当于数据管道,屏蔽了数据转换过程。可以连接到一个设备上,这个设备可以是socket, file,或buffer.

大端与小端

为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit
- 大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
- 小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。

16bit宽的数0x1234在Little-endian(小端)模式(假设从地址0x4000开始存放)为:

内存地址  0x4000    0x4001存放内容  0x34      0x12

16bit宽的数0x1234在BIG-endian(大端)模式

内存地址  0x4000    0x4001存放内容  0x12      0x34

数在据的表达方式,实际上是大端序更符合人们的阅读方式。

文件操作

· QFlie:访问本地文件或者嵌入资源;
· QTemporaryFile:创建和访问本地文件系统的临时文件;
· QBuffer:读写QByteArray;
· QProcess:运行外部程序,处理进程间通讯;
· QTcpSocket:TCP协议网络数据传输;
· QUdpSocket:传输 UDP 报文;
· QSslSocket:使用 SSL/TLS 传输数据;
· QFileDevice:Qt5新增加的类,提供了有关文件操作的通用实现。

QProcess、QTcpSocket、QUdpSoctet和QSslSocket是顺序访问设备。所谓“顺序访问”,是指它们的数据只能访问一遍:从头走到尾,从第一个字节开始访问,直到最后一个字节,中途不能返回去读取上一个字节;QFile、QTemporaryFile和QBuffer是随机访问设备,可以访问任意位置任意次数,还可以使用QIODevice::seek()函数来重新定位文件访问位置指针。

QIODevice

QIODevice类是所有输入输出IO类的基础类,为IO类提供了统一的调用接口,因此我们称QIODevice类以及其派生类为IO类。

为设备提供了一个共同的实现和抽象接口,它支持读取和写入像QFile、QBuffer和QTcpSocket等以块为单位的数据。
QIODevice是抽象类,不能被实例化(instantiated),但是利用它定义的接口来提供独立于设备的I / O功能是普遍的。

枚举值描述QIODevice::NotOpen      //未打开QIODevice::ReadOnly     //以只读方式打开QIODevice::WriteOnly    //以只写方式打开QIODevice::ReadWrite    //以读写方式打开QIODevice::Append       //以追加的方式打开,新增加的内容将被追加到文件末尾QIODevice::Truncate     //以重写的方式打开,在写入新的数据时会将游标设置在文件开头QIODevice::Text         //在读取时,将行结束符转换成 \n;在写入时,将行结束符转换成本地格式,例如 Win32 平台上是 \r\nQIODevice::Unbuffered   //缓存

服务端源码

cpp文件

#include "widget.h"#include "ui_widget.h"#include <QDateTime>#include <QIODevice>#include <QByteArray>Widget::Widget(QWidget *parent) :    QWidget(parent),    ui(new Ui::Widget){    ui->setupUi(this);    connect(&timer,SIGNAL(timeout()),this,SLOT(onSendDatagram()));}Widget::~Widget(){    delete ui;}double Widget::temperature() const{    return -20.0 + (2.0 * std::rand() / (RAND_MAX + 1.0));}double Widget::humidity() const{    return 20.0 + (2.0 * std::rand() / (RAND_MAX + 1.0));}double Widget::altitude() const{    return 7000 + (100.0 * std::rand() / (RAND_MAX + 1.0));}void Widget::onSendDatagram(){    //用于存放发送的数据报    QByteArray datagram;    //QIODevice::WriteOnly 以只写方式打开    QDataStream out(&datagram, QIODevice::WriteOnly);    //设置数据序列化格式的版本号,建议看到版本    out.setVersion(QDataStream::Qt_5_6);    out<<QDateTime::currentDateTime() <<temperature() << humidity() <<altitude();    //UDP广播    //发送者把数据发送到端口号,需要接受者绑定该端口号    mUdpSocket.writeDatagram(datagram,QHostAddress::Broadcast ,5824);    //发送本机    mUdpSocket.writeDatagram(datagram,QHostAddress::LocalHost ,5824);    //指定IP    QHostAddress serverAddress = QHostAddress("192.168.86.12");    //datagram.size()大小,不包含'\0' ,qstrlen()包含'\0'    //datagram.data()所存储的数据对象,返回一个指针    mUdpSocket.writeDatagram(datagram.data(), datagram.size(),serverAddress, 5824);}void Widget::on_pushButton_2_clicked(){     timer.start(1000);}void Widget::on_pushButton_clicked(){    this->close();}

UDP接收端

接收端源码

#include "widgetclient.h"#include "ui_widgetclient.h"#include <QGridLayout>#include <QTimer>#include <QDateTime>WidgetClient::WidgetClient(QWidget *parent) :    QWidget(parent),    ui(new Ui::WidgetClient){    ui->setupUi(this);    //此处的bind是个重载函数,连接本机的port端口,采用ShareAddress模式(即允许其它的服务连接到相同的地址和端口,特别是    //用在多客户端监听同一个服务器端口等时特别有效),和ReuseAddressHint模式(重新连接服务器)    mUdpSocket.bind(5824, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);    //readyRead()信号是每当有新的数据来临时就被触发    connect(&mUdpSocket,SIGNAL(readyRead()),SLOT(onProcessPendingDatagrams()));    mDataLabel = new QLabel(tr("Data:"));    mTimeLabel = new QLabel(tr("Time:"));    mTemperatureLabel = new QLabel(tr("Temperature:"));    mhumidtyLabel = new QLabel(tr("Hunidity:"));    mAltitudeLabel = new QLabel(tr("Altitude:"));    mDateLineEdit = new QLineEdit;    mTimeLineEdit = new QLineEdit;    mTemperatureLineEdit = new QLineEdit;    mHunidityLineEdit = new QLineEdit;    mAltitudeLineEdit = new QLineEdit;    mDateLineEdit->setReadOnly(true);    mTimeLineEdit->setReadOnly(true);    mTemperatureLineEdit->setReadOnly(true);    mHunidityLineEdit->setReadOnly(true);    mAltitudeLineEdit->setReadOnly(true);    QGridLayout *mainLayout = new QGridLayout;    mainLayout->addWidget(mDataLabel,0,0);    mainLayout->addWidget(mDateLineEdit,0,1);    mainLayout->addWidget(mTimeLabel,1,0);    mainLayout->addWidget(mTimeLineEdit,1,1);    mainLayout->addWidget(mTemperatureLabel,2,0);    mainLayout->addWidget(mTemperatureLineEdit,2,1);    mainLayout->addWidget(mhumidtyLabel,3,0);    mainLayout->addWidget(mHunidityLineEdit,3,1);    mainLayout->addWidget(mAltitudeLabel,4,0);    mainLayout->addWidget(mAltitudeLineEdit,4,1);    setLayout(mainLayout);    setWindowTitle(tr("Weather Station"));}WidgetClient::~WidgetClient(){    delete ui;}void WidgetClient::onProcessPendingDatagrams(){    QByteArray datagram;    while(mUdpSocket.hasPendingDatagrams()) //是否有数据包等待读取    {        //pendingDatagramSize为返回第一个在等待读取报文的size,resize函数是把datagram的size归一化到参数size的大小一样        datagram.resize(mUdpSocket.pendingDatagramSize()); //        //将读取到的不大于datagram.size()大小数据输入到datagram.data()中,datagram.data()返回的是一个字节数组中存储        //数据位置的指针        mUdpSocket.readDatagram(datagram.data(), datagram.size());    }    QDateTime dateTime;    double temperature;    double humidity;    double altitude;    QDataStream in(&datagram,QIODevice::ReadOnly); //从datagram中读取数据    in.setVersion(QDataStream::Qt_5_6);    //因为其属性为只读,所以是输入,值得注意的接收顺序与发送一致    in>>dateTime >> temperature >>humidity >>altitude;    mDateLineEdit->setText(dateTime.date().toString());    mTimeLineEdit->setText(dateTime.time().toString());    mTemperatureLineEdit->setText(tr("%1 C").arg(temperature));    mHunidityLineEdit->setText(tr("%1%").arg(humidity));    mAltitudeLineEdit->setText(tr("%1 m").arg(altitude));}

下载地址
http://download.csdn.net/download/osean_li/10112271

效果图
这里写图片描述

原创粉丝点击