今天初学udp传输协议,先了解了一下DUP的内容,UDP是一个用户数据报协议,是一个传输层的协议。其传输速度快。但是传输的质量有时不好。
今天我学习了一下udp需要用qt来进行的操作,下面介绍一下我遇到的问题和解决方法
首先我建立了一个qt的项目,发现出现问题,
widget不是类或命名空间,经过排查发现是是因为这个widget应该是自己创建的窗口的名字而不是同意的widget
但是在添加头文件是遇到问题,C1083无法打开包括文件,看了好长时间才发现是因为咱们用UDP所需的头文件
QAbstractSocket没有在pro中添加QT +=network添加之后发现头文件可以找到了。
现在我们开始编写一个简单的收发的小程序
先编写发送的,发送udp的文件比较简单,主要代码是
我自定义了一个按键,这个按键可以进行发送这个操作,一下发送100条helloworld,先用socket实例化一个对象,sender,让它可以发送文件,函数需要这样几个参数,第一个是信息的内容,第二个是我们发送的地址,第三个是我们发送的端口。这样我们就可以把我们想发送的数据发送到我们想要的地方了。
发送程序比较简单,下面我们来编写一下我们的接收程序。
编写接收程序的时候遇到了不少的问题,我们来一一解决
首先我们编写一个接收程序想要完成的是从刚才我们发送的端口把我们发送的数据取出来,然后进行读取。
那么我们就需要一个函数,查资料得知这个函数是bind(),我们使用了一下这个函数,
uSocket.bind(QHostAddress("127.0.0.1"), PORT);
函数中需要的是地址和我们的端口,这样就能把我们需要的数据读取在我们定义的socket上了。
可是我们怎么判断可以读取呢?
一开始我想用一个叫做hsaPendingDatagrams的函数
while(uSocket->hasPendingDatagrams())
这个函数可以判断在这个端口处有没有阻塞的数据,如果有的话就拿出来读。
下面一个问题就是取出来的数据怎么存储了,想了想还是用了
QByteArray ba;
QByteArrary存储。
可是用发送程序发送之后并不能成功的接收到。那么是什么问题呢?
这时候我想了想,就决定编写了一个控制台程序,来验证是哪里出现了问题。
控制台接收程序如下:
头文件
#ifndef UDPRECEIVER_H
#define UDPRECEIVER_H
#include <QObject>
#include <QUdpSocket>
class UdpReceiver : public QObject
{
Q_OBJECT
public:
UdpReceiver(QObject *p = 0);
~UdpReceiver();
public slots:
void receive();
private:
QUdpSocket *uSocket;
};
#endif // UDPRECEIVER_H
udpreceiver.cpp
#include <QByteArray>
#include <iostream>
#include "UdpReceiver.h"
const quint16 PORT = 2333;
UdpReceiver::UdpReceiver(QObject *p) :
QObject(p)
{
uSocket = new QUdpSocket;
uSocket->bind(QHostAddress("127.0.0.1"), PORT);
connect(uSocket, SIGNAL(readyRead()), this, SLOT(receive()));
}
UdpReceiver::~UdpReceiver()
{
delete uSocket;
}
void UdpReceiver::receive()
{
QByteArray ba;
while(uSocket->hasPendingDatagrams())
{
ba.resize(uSocket->pendingDatagramSize());
uSocket->readDatagram(ba.data(), ba.size());
std::cout << ba.data() << std::endl;
}
}
main.cpp
#include <QCoreApplication>
#include "udpreceiver.h"
#include <iostream>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
UdpReceiver ur;
std::cout << "--- Recevier ---" << std::endl;
return a.exec();
}
再试着运行一下
这时候运行成功了。
后来研究了一下,控制台程序是一直让他在while循环里面进行,虽然表面上没有卡死,但是其实是卡在那里的,有没有什么更好的办法呢?
想了一下,觉得用多线程可能实现这个程序所需要的功能,一个进行判断是否有信息,一个进行读取。
但是后来查了下文档,有一个叫做waitforreadread的函数,已经帮我们实现了这个功能。
我们来使用一下这个函数。
while(uSocket.waitForReadyRead(3000))
{
ba.resize(uSocket.pendingDatagramSize());
uSocket.readDatagram(ba.data(), ba.size());
ui->MessageEdit->append(ba.data());
}
可是这样非但没有运行处想要的效果,而且程序在执行的时候会先卡上一会,然后才能运行。
这是因为什么?
这个函数可以输入一个参数来指示等待的时间,如果不输入的话默认是3s,里面输入的参数是毫秒。
这样程序的意思就是,while,等上3s,然后在判断,这个函数是执行后返回一个布尔值,然后判断一下。
那么怎么样才能用起来呢?
思考了一下,发现是因为我们想问题的顺序不对,这个函数的意思是,我们执行完了之后,他会等待上3s,如果有数据那么就读出来。
所以我们改变了一下我们的函数的顺序
void UdpReceiver::on_ReceiverButton_clicked()
{
ui->MessageEdit->clear();
QUdpSocket uSocket;
uSocket.bind(QHostAddress("127.0.0.1"), PORT);
uSocket.waitForReadyRead(3000);
QByteArray ba;
while(uSocket.hasPendingDatagrams())
{
ba.resize(uSocket.pendingDatagramSize());
uSocket.readDatagram(ba.data(), ba.size());
ui->MessageEdit->append(ba.data());
}
// else
// {
// qDebug()<<"importdefaut"<<ba.data();
// }
//qDebug()<<"等待"<<uSocket.waitForReadyRead(3000);
//ui->MessageEdit->setText(ba[0]);
//QString bb;
//bb=ba;
//ui->MessageEdit->append(bb);
}
然后进行了实验
这时候我们的程序运行成功了。实现了udp的传输和发送。