Qt:83---Demo(UDP单播、广播通信演示案例)

一、单播、广播通用案例

UDP通信是点对点的,所以下面的程序可以作为两个数据方来使用,代码都是相同的

第一步:

  • 创建一个基于QMainWindow的窗体,类名采取默认值。并设计窗体

第二步:

  • 类的定义
//只列出了自己书写的代码,系统的代码省略了
#include <QUdpSocket>
#include <QHostInfo>
#include <QLabel>

class MainWindow : public QMainWindow
{
private:
    QLabel *LabSocketState;//socket状态显示标签
    QUdpSocket *udpSocket; //UDP套接字
    QString getLocalIP();  //获取本地目标地址
private slots:
    //自定义槽函数
    void onSocketStateChange(QAbstractSocket::SocketState socketState);
    void onSocketReadyRead();
};

第三步:

  • 构造函数
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    //设置spin控件可以显示的最大值
    ui->spinLocalPort->setMaximum(65535);
    ui->spinTargetPort->setMaximum(65535);
    
    //设置标签的内容并显示在状态栏和窗体标题中
    LabSocketState=new QLabel(QStringLiteral("Socket状态:"));
    LabSocketState->setMinimumWidth(200);
    ui->statusBar->addWidget(LabSocketState);
    
    //获取本机IP地址显示在comboBox中
    QString localIp=getLocalIP();
    this->setWindowTitle(this->windowTitle()+QStringLiteral("本机IP:")+localIp);
    ui->comboTarget->addItem(localIp);
    
    //创建QUdpSocket对象,并关联信号与槽
    udpSocket=new QUdpSocket(this);
    connect(udpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    connect(udpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}
  • 自定义getLocalIP函数
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::on_actBind_triggered()
{
    quint16 port=ui->spinLocalPort->value();
    if(udpSocket->bind(port))
    {
        ui->plainTextEdit->appendPlainText(QStringLiteral("已成功绑定"));
        ui->plainTextEdit->appendPlainText(QStringLiteral("绑定端口:")+QString::number(udpSocket->localPort()));
        ui->actBind->setEnabled(false);
        ui->actStop->setEnabled(true);
    }
    else
        ui->plainTextEdit->appendPlainText(QStringLiteral("绑定失败"));
}
  • 解除绑定按钮的响应函数 
void MainWindow::on_actStop_triggered()
{
    udpSocket->abort();//重置套接字
    ui->actBind->setEnabled(true);
    ui->actStop->setEnabled(false);
    ui->plainTextEdit->appendPlainText(QStringLiteral("已解除绑定"));
}

第五步:

  • 发送消息按钮的响应函数
void MainWindow::on_btnSendMsg_clicked()
{
    //获取目标地址与端口
    QString targetIP=ui->comboTarget->currentText();
    QHostAddress targetAddr(targetIP);
    quint16 targetPort=ui->spinTargetPort->value();
    
    //发送消息
    QString msg=ui->editMsg->text();
    QByteArray str=msg.toUtf8();
    udpSocket->writeDatagram(str,targetAddr,targetPort);
    
    ui->plainTextEdit->appendPlainText(QStringLiteral("[out]:")+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();
}
  • 广播消息按钮的响应函数
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(QStringLiteral("[broadcast]:")+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();
}

第六步:

  • 自定义onSocketReadyRead槽函数的实现
void MainWindow::onSocketReadyRead()
{
    //hasPendingDatagrams代表如果有数据可以读取
    while(udpSocket->hasPendingDatagrams())
    {
        //定义存取数据的字节数据和大小
        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);
    }
}
  • 自定义onSocketStateChange槽函数的实现
void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{
    //socket的各种状态
    switch (socketState) {
        case QAbstractSocket::UnconnectedState:
            LabSocketState->setText(QStringLiteral("socket状态:UnconnectedState"));
            break;
        case QAbstractSocket::HostLookupState:
            LabSocketState->setText(QStringLiteral("socket状态:HostLookupState"));
            break;
        case QAbstractSocket::ConnectedState:
            LabSocketState->setText(QStringLiteral("socket状态:ConnectedState"));
            break;
        case QAbstractSocket::BoundState:
            LabSocketState->setText(QStringLiteral("socket状态:BoundState"));
            break;
        case QAbstractSocket::ClosingState:
            LabSocketState->setText(QStringLiteral("socket状态:ClosingState"));
            break;
        case QAbstractSocket::ListeningState:
            LabSocketState->setText(QStringLiteral("socket状态:ListeningState"));
            break;
    }
}

演示效果:

二、单播案例

  • UDP其实没有客户端与服务端的概念,双方都是对等的。此处为了方便演示,采取了客户端与服务端的说法

客户端

//客户端类
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
private:
    Ui::Widget *ui;
    QUdpSocket* udpSocket;//套接字
private slots:
    void bindServer();//绑定端口
    void recMsg();//接受消息
    void closeUdpClient();//关闭套接字
};
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    udpSocket=new QUdpSocket(this);
    connect(udpSocket,SIGNAL(readyRead()),this,SLOT(recMsg()));//接收数据
    connect(ui->closeUdpBtn,SIGNAL(clicked()),this,SLOT(closeUdpClient()));//点击关闭按钮
    connect(ui->bindPushBtn,SIGNAL(clicked()),this,SLOT(bindServer()));//点击绑定按钮
}

void Widget::recMsg()//接受信息
{
    while(udpSocket->hasPendingDatagrams())//如果有数据包传入
    {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());//得到数据包大小

        udpSocket->readDatagram(datagram.data(),datagram.size());//读取数据
        QString msg=QString::fromUtf8(datagram.data());//数据类型转换
        ui->recvTBrowser->append(msg);
    }
}

void Widget::bindServer()//绑定端口
{
    qint32 port=ui->portLineEdit->text().toInt();//得到端口号
    bool result=udpSocket->bind(port);//绑定端口号
    if(result)//绑定成功
    {
        QMessageBox::warning(this,"Information","create udp clinet success");
    }
    else//绑定失败
    {
        QMessageBox::warning(this,"Error Information","create udp clinet failed");
    }
}

void Widget::closeUdpClient()//关闭套接字
{
    udpSocket->close();//关闭套接字
}

服务端

//服务端类
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
private:
    Ui::Widget *ui;
    QUdpSocket* udpSocket;//套接字
private slots:
    void sendMsg();//发送信息
};
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    udpSocket=new QUdpSocket(this);
    connect(ui->sendMsgBtn,SIGNAL(clicked()),this,SLOT(sendMsg()));//点击发送按钮
}

void Widget::sendMsg()//发送数据
{
    qint32 port=ui->portLineEdit->text().toInt();//得到端口号
    QString msg=ui->sendMsgLineEdit->text();//得到数据
    QByteArray datagram=msg.toUtf8().data();//数据类型转换
    if(datagram.isEmpty())//为空退出
        return;
    //写入数据,并判断写入数据长度是否正确
    int msgLen=0;
    if(msgLen=udpSocket->writeDatagram(datagram.data(),datagram.size(),\
                                       QHostAddress::Broadcast,port)==datagram.size())
    {
        return;
    }
}

演示效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董哥的黑板报

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值