目录
例子展示:
上次写了个tcp/ip 的网络例子,本章记录有关UDP数据传输的例子,本例子多多学习,将会是一个很有意思的例子。
ok,话不多说,让我们看看这个例子吧,老规矩,先上结果图吧!
这里先讲述UDP的基本知识点吧:
UDP 通信概述
UDP (User Datagram Protocol , 用户数据报协议)是轻量的、不可靠的、面向数据报( datagram ) 、 无连接的协议,它可以用于对可靠性要求不高的场合。 与 TCP 通信不同,两个程序之间进行 UDP 通信无需预先建立持久的 socket 连接, UDP 每次发送数据报都需要指定目标地址和端口。
QUdpSocket 类用于实现 UDP 通信,它从 QAbstractSocket 类继承,因而与 QTcpSocket 共享大部分的接口函数 。主要区别是 QUdpSocket 以数据报传输数据,而不是以连续的数据流。发送数据报使用函数 QUdpSocket: :writeDatagram(), 数据报的长度一般少于 512 字节 , 每个数据报包含发送者和接收者的 IP 地址和l端口等信息 。
UDP 消息传送有单播、广播、组播三种模式:
本例子为单播与广播,组播内容需要两台电脑去测试这里就不先写了,想要了解可以私信我,可以把例子给你。
代码解析部分:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QUdpSocket>
#include <QLabel>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
QLabel *LabSocketState;//socket状态显示标签
QUdpSocket *udpSocket;//
QString getLocalIP();//获取本机IP地址
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
//自定义槽函数
void onSocketStateChange(QAbstractSocket::SocketState socketState);
void onSocketReadyRead();//读取socket传入的数据
//
void on_actStart_triggered();
void on_actStop_triggered();
void on_actClear_triggered();
void on_btnSend_clicked();
void on_actHostInfo_triggered();
void on_btnBroadcast_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
QUdpSocket 类型 的私有变量 udpSocket 是用于 UDP 通信的 socket 。
定义了两个自定义槽函数,onSocketStateChange()与 udpSocket 的stateChange()信号关联, 用于显示 udpSocket 当前的状态 ; onSocketReadyRead()信号与 udpSocket 的 readyRead()信号关联 ,用于读取缓冲区的数据报 。
关联部分:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
LabSocketState=new QLabel("Socket状态:");//
LabSocketState->setMinimumWidth(200);
ui->statusBar->addWidget(LabSocketState);
QString localIP=getLocalIP();//本机IP
this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);
ui->comboTargetIP->addItem(localIP);
udpSocket=new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
connect(udpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
onSocketStateChange(udpSocket->state());
connect(udpSocket,SIGNAL(readyRead()),
this,SLOT(onSocketReadyRead()));
}
MainWindow::~MainWindow()
{
udpSocket->abort();
delete udpSocket;
delete ui;
}
对应实现部分:
获取当前ip的方法
QString MainWindow::getLocalIP()
{
QString hostName=QHostInfo::localHostName();//本地主机名
QHostInfo hostInfo=QHostInfo::fromName(hostName);
QString localIP="";
QList<QHostAddress> addList=hostInfo.addresses();//
if (!addList.isEmpty())
for (int i=0;i<addList.count();i++)
{
QHostAddress aHost=addList.at(i);
if (QAbstractSocket::IPv4Protocol==aHost.protocol())
{
localIP=aHost.toString();
break;
}
}
return localIP;
}
两个函数,一个来判断网络的状态,一个是用来由数据读取数据并表示出来:
void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{
switch(socketState)
{
case QAbstractSocket::UnconnectedState:
LabSocketState->setText("scoket状态:UnconnectedState");
break;
case QAbstractSocket::HostLookupState:
LabSocketState->setText("scoket状态:HostLookupState");
break;
case QAbstractSocket::ConnectingState:
LabSocketState->setText("scoket状态:ConnectingState");
break;
case QAbstractSocket::ConnectedState:
LabSocketState->setText("scoket状态:ConnectedState");
break;
case QAbstractSocket::BoundState:
LabSocketState->setText("scoket状态:BoundState");
break;
case QAbstractSocket::ClosingState:
LabSocketState->setText("scoket状态:ClosingState");
break;
case QAbstractSocket::ListeningState:
LabSocketState->setText("scoket状态:ListeningState");
}
}
void MainWindow::onSocketReadyRead()
{//读取收到的数据报
while(udpSocket->hasPendingDatagrams())
{
//不能用下面的方法读取发送端的IP地址和端口
// QString peerAddr=udpSocket->peerAddress().toString();
// quint16 peerPort=udpSocket->peerPort();
// QString peer="[From "+peerAddr+":"+QString::number(peerPort)+"] ";
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
QHostAddress peerAddr;
quint16 peerPort;
udpSocket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);
QString str=datagram.data();
QString peer="[From "+peerAddr.toString()+":"+QString::number(peerPort)+"] ";
ui->plainTextEdit->appendPlainText(peer+str);
}
}
绑定端口:
void MainWindow::on_actStart_triggered()
{//绑定端口
// QHostAddress addr("192.168.1.106");
quint16 port=ui->spinBindPort->value(); //本机UDP端口
// if (udpSocket->bind(QHostAddress::LocalHost,port))//绑定端口成功
if (udpSocket->bind(port))//绑定端口成功
{
ui->plainTextEdit->appendPlainText("**已成功绑定");
ui->plainTextEdit->appendPlainText("**绑定端口:"
+QString::number(udpSocket->localPort()));
// ui->plainTextEdit->appendPlainText("**绑定IP:"
// +udpSocket->localAddress().toString());
ui->actStart->setEnabled(false);
ui->actStop->setEnabled(true);
}
else
ui->plainTextEdit->appendPlainText("**绑定失败");
}
解除绑定 :
void MainWindow::on_actStop_triggered()
{//解除绑定
udpSocket->abort(); //不能解除绑定
ui->actStart->setEnabled(true);
ui->actStop->setEnabled(false);
ui->plainTextEdit->appendPlainText("**已解除绑定");
}
清除文本:
void MainWindow::on_actClear_triggered()
{
ui->plainTextEdit->clear();
}
发送消息 按钮 :
void MainWindow::on_btnSend_clicked()
{//发送消息 按钮
QString targetIP=ui->comboTargetIP->currentText(); //目标IP
QHostAddress targetAddr(targetIP);
quint16 targetPort=ui->spinTargetPort->value();//目标port
QString msg=ui->editMsg->text();//发送的消息内容
QByteArray str=msg.toUtf8();
udpSocket->writeDatagram(str,targetAddr,targetPort); //发出数据报
ui->plainTextEdit->appendPlainText("[out] "+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
}
本机地址 按钮
void MainWindow::on_actHostInfo_triggered()
{//本机地址 按钮
QString hostName=QHostInfo::localHostName();//本地主机名
ui->plainTextEdit->appendPlainText("本机主机名:"+hostName+"\n");
QHostInfo hostInfo=QHostInfo::fromName(hostName);
QList<QHostAddress> addList=hostInfo.addresses();//
if (!addList.isEmpty())
for (int i=0;i<addList.count();i++)
{
QHostAddress aHost=addList.at(i);
if (QAbstractSocket::IPv4Protocol==aHost.protocol())
{
QString IP=aHost.toString();
ui->plainTextEdit->appendPlainText("本机IP地址:"+aHost.toString());
if (ui->comboTargetIP->findText(IP)<0)
ui->comboTargetIP->addItem(IP);
}
}
}
广播消息:
void MainWindow::on_btnBroadcast_clicked()
{ //广播消息 按钮
quint16 targetPort=ui->spinTargetPort->value(); //目标端口
QString msg=ui->editMsg->text();
QByteArray str=msg.toUtf8();
udpSocket->writeDatagram(str,QHostAddress::Broadcast,targetPort);
ui->plainTextEdit->appendPlainText("[broadcast] "+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
}
例子下载连接:
链接:例子连接下载传送门 提取码:gtk3
功能就简单写到这里了,喜欢的朋友可以关注我,一起来提高技术,需要资源的可以私信我,有的免费分享。