从零开发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
效果图
- 从零开发B/S机架应用程序(三)-UDP
- 从零开发B/S机架应用程序(一)
- 从零开发B/S机架应用程序(二)
- 从零开发B/S机架应用程序(四)-TCP
- 从零开发B/S机架应用程序(五)
- pb11开发b/s(三)
- 智能手机Smartphone开发从零起步(三)
- 【cocos2d-x游戏开发】 从零单排之(三)
- 从零冲击Erlang(三)
- 从零开发一个完整的Android项目(三)——常量的定义
- Android开发从零单排(一)
- 使用NetBeans进行B/S结构的商业应用开发(三)
- Python3从零学习(三)
- C++ 从零单排(5)- ACM三和总结
- PHP从零单排(三)PHP中的session
- 从零学Android(三)、Activity页面的跳转
- 从零学习Belief Propagation算法(三)
- 从零搭建直播聊天平台(三.video.js)
- 设计模式学习---第九节:抽象工厂模式
- 计算机网络 学习摘要(8)
- 命题逻辑的soundness可靠性和completeness完备性
- 集合总结
- C++之局部变量
- 从零开发B/S机架应用程序(三)-UDP
- Spring中@Transactional用法深度分析之一
- AOP
- JavaScript创建文本节点
- OS技术交流群(200255678)
- 百度天工云mqtt测试中的一个BUG
- PB开发微信公众号
- IOC
- python异常