《 QT5.9 c++ 开发指南》 一个简单例子学会 UDP网络编程

目录

例子展示:

UDP 通信概述

代码解析部分:


 例子展示:

    上次写了个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 

功能就简单写到这里了,喜欢的朋友可以关注我,一起来提高技术,需要资源的可以私信我,有的免费分享。 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值