UDP概念
UDP(用户数据报协议)是一个简单的面向数据报的传输层协议。提供的是非面向连接的、不可靠的数据流传输。UDP不提供可靠性,也不提供报文到达确认、排序以及流量控制等功能。它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。因此报文可能会丢失、重复以及乱序等。但由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
UDP传输方式
UDP有单播、广播、组播
只有UDP有广播和多播, TCP只能进行点对点的单播, 多播的重点是高效的把同一个包尽可能多的发送到不同的,甚至可能是未知的设备。但是TCP连接是一对一明确的,只能单播。
文中涉及到所有的代码下载地址
代码下载。这里有文章中所有的代码。如果没有积分可以私聊我发你。
单播
服务端(发送者)
服务器端不需要绑定。只需要在发送时指定对方IP以及端口即可。
m_sender->writeDatagram(dataGram.data(),// 发送内容 dataGram.size(),// 发送长度 QHostAddress("192.168.0.108"), // 对方IP 6666);//对方端口
客户端(接收者)
客户端需要提前将本地IP和对应的端口进行绑定。然后关联readyRead信号。进行对应的实时读取。
下面这段代码是提前进行绑定和对应的信号槽关联
groupAddress = QHostAddress("192.168.0.112"); // 本地地址 int port1 = 6666; // 本地端口 bool ret = m_receiver->bind(groupAddress,port1,QUdpSocket::ShareAddress); if(ret == false) { QMessageBox::warning(this,"error", "绑定失败"); } //当接收端接收到数据时,就会发送readRead信号 connect(m_receiver,&QUdpSocket::readyRead,this,&ReceiverWidget::processData);
下面这段代码是槽函数的一个实时读取并显示在标签上。
void ReceiverWidget::processData() { QString strData; //有未处理的数据报 while(m_receiver->hasPendingDatagrams()) { QByteArray dataGram; //读取的数据报大小 dataGram.resize(m_receiver->pendingDatagramSize()); m_receiver->readDatagram(dataGram.data(),dataGram.size()); ui->textBrowser->insertPlainText(dataGram); //将接收到的数据显示到标签上 ui->textBrowser->insertPlainText("\n"); //将接收到的数据显示到标签上 } }
效果图
组播
组播相当于是在广播的基础上在加入组播。
服务端(发送者)
服务器端不需要绑定。只需要在发送时指定对方IP以及端口即可。
m_sender=new QUdpSocket(this); QByteArray dataGram= ui->lineEdit->text().toUtf8(); QHostAddress appaddr; m_sender->writeDatagram(dataGram.data(), dataGram.size(), QHostAddress("224.0.0.0"),// 组播地址 7755);
客户端(接收者)
客户端需要对应的端口进行绑定。并加入到组播地址中,然后关联readyRead信号。进行对应的实时读取。
下面这段代码是提前进行绑定、加入组并关联信号和槽
groupAddress = QHostAddress("224.0.0.0"); // 组播地址 port = 7755; m_receiver = new QUdpSocket(this); bool aa = m_receiver->bind(QHostAddress::AnyIPv4, port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint); if(false == aa) { qDebug() << "绑定失败!"; } // 加入组播 bool cc = m_receiver->joinMulticastGroup(groupAddress); if(false == cc) { qDebug() << "加入组播失败!"; } //当接收端接收到数据时,就会发送readRead信号 connect(m_receiver, &QUdpSocket::readyRead, this, &ReceiverWidget::processData);
下面这段代码是槽函数的一个实时读取并显示在标签上。
void ReceiverWidget::processData() { QString strData; //有未处理的数据报 while(m_receiver->hasPendingDatagrams()) { QByteArray dataGram; //读取的数据报大小 dataGram.resize(m_receiver->pendingDatagramSize()); m_receiver->readDatagram(dataGram.data(),dataGram.size()); ui->textBrowser->insertPlainText(dataGram); //将接收到的数据显示到标签上 ui->textBrowser->insertPlainText("\n"); //将接收到的数据显示到标签上 } }
效果图
广播
广播只需要绑定端口即可。
服务器(发送者)
不需要绑定。发送时仅确定端口即可。
QByteArray dataGram= ui->lineEdit->text().toUtf8(); m_sender->writeDatagram(dataGram.data(), dataGram.size(), QHostAddress::Broadcast, 7755);
客户端(接收者)
需要绑定所有的Ip地址(AnyIPv4
)以及对应的端口。然后关联readyRead信号。进行对应的实时读取。
下面这段代码是提前进行绑定和对应的信号槽关联。
下面这段代码是提前进行绑定和对应的信号槽关联
port = 7755; m_receiver = new QUdpSocket(this); bool aa = m_receiver->bind(QHostAddress::AnyIPv4, port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint); if(false == aa) { qDebug() << "绑定失败!"; } //当接收端接收到数据时,就会发送readRead信号 connect(m_receiver, &QUdpSocket::readyRead, this, &ReceiverWidget::processData);
下面这段代码是槽函数的一个实时读取并显示在标签上。
void ReceiverWidget::processData() { QString strData; //有未处理的数据报 while(m_receiver->hasPendingDatagrams()) { QByteArray dataGram; //读取的数据报大小 dataGram.resize(m_receiver->pendingDatagramSize()); m_receiver->readDatagram(dataGram.data(),dataGram.size()); ui->textBrowser->insertPlainText(dataGram); //将接收到的数据显示到标签上 ui->textBrowser->insertPlainText("\n"); //将接收到的数据显示到标签上 } }
效果图