Java教程

网络编程——UDP通信

本文主要是介绍网络编程——UDP通信,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

单播和广播

代码

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QUdpSocket>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QTextBrowser>
#include <QLabel>
#include <QComboBox>
#include <QSpinBox>
#include <QHostInfo>
#include <QLineEdit>
#include <QNetworkInterface>
#include <QDebug>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    /* Udp 通信套接字 */
    QUdpSocket *udpSocket;
    /* 按钮 */
    QPushButton *pushButton[5];
    /* 标签文本 */
    QLabel *label[3];
    /* 水平容器 */
    QWidget *hWidget[3];
    /* 水平布局 */
    QHBoxLayout *hBoxLayout[3];
    /* 垂直容器 */
    QWidget *vWidget;
    /* 垂直布局 */
    QVBoxLayout *vBoxLayout;
    /* 文本浏览框 */
    QTextBrowser *textBrowser;
    /* 用于显示本地 ip */
    QComboBox *comboBox;
    /* 用于选择端口 */
    QSpinBox *spinBox[2];
    /* 文本输入框 */
    QLineEdit *lineEdit;
    /* 存储本地的 ip 列表地址 */
    QList<QHostAddress> IPlist;
    /* 获取本地的所有 ip */
    void getLocalHostIP();
private slots:
    /* 绑定端口 */
    void bindPort();
    /* 解绑端口 */
    void unbindPort();
    /* 清除文本框时的内容 */
    void clearTextBrowser();
    /* 接收到消息 */
    void receiveMessages();
    /* 发送消息 */
    void sendMessages();
    /* 广播消息 */
    void sendBroadcastMessages();
    /* 连接状态改变槽函数 */
    void socketStateChange(QAbstractSocket::SocketState);
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    /* 设置主窗体的位置与大小 */
    this->setGeometry(0, 0, 800, 480);

    /* udp 套接字 */
    udpSocket = new QUdpSocket(this);

    /* 绑定端口按钮 */
    pushButton[0] = new QPushButton();
    /* 解绑端口按钮 */
    pushButton[1] = new QPushButton();
    /* 清空聊天文本按钮 */
    pushButton[2] = new QPushButton();
    /* 发送消息按钮 */
    pushButton[3] = new QPushButton();
    /* 广播消息按钮 */
    pushButton[4] = new QPushButton();

    /* 水平布局一 */
    hBoxLayout[0] = new QHBoxLayout();
    /* 水平布局二 */
    hBoxLayout[1] = new QHBoxLayout();
    /* 水平布局三 */
    hBoxLayout[2] = new QHBoxLayout();
    /* 水平布局四 */
    hBoxLayout[3] = new QHBoxLayout();

    /* 水平容器一 */
    hWidget[0] = new QWidget();
    /* 水平容器二 */
    hWidget[1] = new QWidget();
    /* 水平容器三 */
    hWidget[2] = new QWidget();


    vWidget = new QWidget();
    vBoxLayout = new QVBoxLayout();

    /* 标签实例化 */
    label[0] = new QLabel();
    label[1] = new QLabel();
    label[2] = new QLabel();

    lineEdit = new QLineEdit();
    comboBox = new QComboBox();
    spinBox[0] = new QSpinBox();
    spinBox[1] = new QSpinBox();
    textBrowser = new QTextBrowser();

    label[0]->setText("目标 IP 地址:");
    label[1]->setText("绑定端口:");
    label[2]->setText("目标端口:");

    /* 设置标签根据文本文字大小自适应大小 */
    label[0]->setSizePolicy(QSizePolicy::Fixed,
    QSizePolicy::Fixed);
    label[1]->setSizePolicy(QSizePolicy::Fixed,
    QSizePolicy::Fixed);
    label[2]->setSizePolicy(QSizePolicy::Fixed,
    QSizePolicy::Fixed);

    /* 设置端口号的范围,注意不要与主机的已使用的端口号冲突 */
    spinBox[0]->setRange(10000, 99999);
    spinBox[1]->setRange(10000, 99999);

    pushButton[0]->setText("绑定端口");
    pushButton[1]->setText("解除绑定");
    pushButton[2]->setText("清空文本");
    pushButton[3]->setText("发送消息");
    pushButton[4]->setText("广播消息");

    /* 设置停止监听状态不可用 */
    pushButton[1]->setEnabled(false);

    /* 设置输入框默认的文本 */
    lineEdit->setText("您好!");

    /* 水平布局一添加内容 */
    hBoxLayout[0]->addWidget(pushButton[0]);
    hBoxLayout[0]->addWidget(pushButton[1]);
    hBoxLayout[0]->addWidget(pushButton[2]);

    /* 设置水平容器的布局为水平布局一 */
    hWidget[0]->setLayout(hBoxLayout[0]);

    hBoxLayout[1]->addWidget(label[0]);
    hBoxLayout[1]->addWidget(comboBox);
    hBoxLayout[1]->addWidget(label[1]);
    hBoxLayout[1]->addWidget(spinBox[0]);
    hBoxLayout[1]->addWidget(label[2]);
    hBoxLayout[1]->addWidget(spinBox[1]);

    /* 设置水平容器的布局为水平布局二 */
    hWidget[1]->setLayout(hBoxLayout[1]);

    /* 水平布局三添加内容 */
    hBoxLayout[2]->addWidget(lineEdit);
    hBoxLayout[2]->addWidget(pushButton[3]);
    hBoxLayout[2]->addWidget(pushButton[4]);

    /* 设置水平容器三的布局为水平布局一 */
    hWidget[2]->setLayout(hBoxLayout[2]);

    /* 垂直布局添加内容 */
    vBoxLayout->addWidget(textBrowser);
    vBoxLayout->addWidget(hWidget[1]);
    vBoxLayout->addWidget(hWidget[0]);
    vBoxLayout->addWidget(hWidget[2]);

    /* 设置垂直容器的布局为垂直布局 */
    vWidget->setLayout(vBoxLayout);

    /* 居中显示 */
    setCentralWidget(vWidget);

    /* 获取本地 ip */
    getLocalHostIP();

    /* 信号槽连接 */
    connect(pushButton[0], SIGNAL(clicked()),
            this, SLOT(bindPort()));
    connect(pushButton[1], SIGNAL(clicked()),
            this, SLOT(unbindPort()));
    connect(pushButton[2], SIGNAL(clicked()),
            this, SLOT(clearTextBrowser()));
    connect(pushButton[3], SIGNAL(clicked()),
            this, SLOT(sendMessages()));
    connect(pushButton[4], SIGNAL(clicked()),
            this, SLOT(sendBroadcastMessages()));
    connect(udpSocket, SIGNAL(readyRead()),
            this, SLOT(receiveMessages()));
    connect(udpSocket,
            SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,
            SLOT(socketStateChange(QAbstractSocket::SocketState)));

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::bindPort()
{
    quint16 port = spinBox[0]->value();

    /* 绑定端口需要在 socket 的状态为 UnconnectedState */
    if (udpSocket->state() != QAbstractSocket::UnconnectedState)
        udpSocket->close();

    if (udpSocket->bind(port)) {
        textBrowser->append("已经成功绑定端口:"
                            + QString::number(port));

        /* 设置界面中的元素的可用状态 */
        pushButton[0]->setEnabled(false);
        pushButton[1]->setEnabled(true);
        spinBox[1]->setEnabled(false);
    }
}

void MainWindow::unbindPort()
{
    /* 解绑,不再监听 */
    udpSocket->abort();

    /* 设置界面中的元素的可用状态 */
    pushButton[0]->setEnabled(true);
    pushButton[1]->setEnabled(false);
    spinBox[1]->setEnabled(true);
}

/* 获取本地 IP */
void MainWindow::getLocalHostIP()
{
    // /* 获取主机的名称 */
    // QString hostName = QHostInfo::localHostName();

    // /* 主机的信息 */
    // QHostInfo hostInfo = QHostInfo::fromName(hostName);

    // /* ip 列表,addresses 返回 ip 地址列表,注意主机应能从路由器获取到
    // * IP,否则可能返回空的列表(ubuntu 用此方法只能获取到环回 IP) */
    // IPlist = hostInfo.addresses();
    // qDebug()<<IPlist<<endl;

    // /* 遍历 IPlist */
    // foreach (QHostAddress ip, IPlist) {
    // if (ip.protocol() == QAbstractSocket::IPv4Protocol)
    // comboBox->addItem(ip.toString());
    // }

    /* 获取所有的网络接口,
    * QNetworkInterface 类提供主机的 IP 地址和网络接口的列表 */
    QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();

    /* 遍历 list */
    foreach (QNetworkInterface interface, list) {
        /* QNetworkAddressEntry 类存储 IP 地址子网掩码和广播地址 */
        QList<QNetworkAddressEntry> entryList
        = interface.addressEntries();

        /* 遍历 entryList */
        foreach (QNetworkAddressEntry entry, entryList) {
            /* 过滤 IPv6 地址,只留下 IPv4 */
            if (entry.ip().protocol() ==
            QAbstractSocket::IPv4Protocol) {
                comboBox->addItem(entry.ip().toString());
                /* 添加到 IP 列表中 */
                IPlist<<entry.ip();
            }
        }
    }
}

/* 清除文本浏览框里的内容 */
void MainWindow::clearTextBrowser()
{
    /* 清除文本浏览器的内容 */
    textBrowser->clear();
}

/* 客户端接收消息 */
void MainWindow::receiveMessages()
{
    /* 局部变量,用于获取发送者的 IP 和端口 */
    QHostAddress peerAddr;
    quint16 peerPort;

    /* 如果有数据已经准备好 */
    while (udpSocket->hasPendingDatagrams()) {
        /* udpSocket 发送的数据报是 QByteArray 类型的字节数组 */
        QByteArray datagram;

        /* 重新定义数组的大小 */
        datagram.resize(udpSocket->pendingDatagramSize());

        /* 读取数据,并获取发送方的 IP 地址和端口 */
        udpSocket->readDatagram(datagram.data(),
                                datagram.size(),
                                &peerAddr,
                                &peerPort);
        /* 转为字符串 */
        QString str = datagram.data();

        /* 显示信息到文本浏览框窗口 */
        textBrowser->append("接收来自"
                            + peerAddr.toString()
                            + ":"
                            + QString::number(peerPort)
                            + str);
    }
}

/* 客户端发送消息 */
void MainWindow::sendMessages()
{
    /* 文本浏览框显示发送的信息 */
    textBrowser->append("发送:" + lineEdit->text());

    /* 要发送的信息,转为 QByteArray 类型字节数组,数据一般少于 512 个字节 */
    QByteArray data = lineEdit->text().toUtf8();

    /* 要发送的目标 Ip 地址 */
    QHostAddress peerAddr = IPlist[comboBox->currentIndex()];

    /* 要发送的目标端口号 */
    quint16 peerPort = spinBox[1]->value();

    /* 发送消息 */
    udpSocket->writeDatagram(data, peerAddr, peerPort);
}

void MainWindow::sendBroadcastMessages()
{
    /* 文本浏览框显示发送的信息 */
    textBrowser->append("发送:" + lineEdit->text());

    /* 要发送的信息,转为 QByteArray 类型字节数组,数据一般少于 512 个字节 */
    QByteArray data = lineEdit->text().toUtf8();

    /* 广播地址,一般为 255.255.255.255,
    * 同一网段内监听目标端口的程序都会接收到消息 */
    QHostAddress peerAddr = QHostAddress::Broadcast;

    /* 要发送的目标端口号 */
    quint16 peerPort = spinBox[1]->text().toInt();

    /* 发送消息 */
    udpSocket->writeDatagram(data, peerAddr, peerPort);
}
/* socket 状态改变 */
void MainWindow::socketStateChange(QAbstractSocket::SocketState state)
{
    switch (state) {
        case QAbstractSocket::UnconnectedState:
            textBrowser->append("scoket 状态:UnconnectedState");
            break;
        case QAbstractSocket::ConnectedState:
            textBrowser->append("scoket 状态:ConnectedState");
            break;
        case QAbstractSocket::ConnectingState:
            textBrowser->append("scoket 状态:ConnectingState");
            break;
        case QAbstractSocket::HostLookupState:
            textBrowser->append("scoket 状态:HostLookupState");
            break;
        case QAbstractSocket::ClosingState:
            textBrowser->append("scoket 状态:ClosingState");
            break;
        case QAbstractSocket::ListeningState:
            textBrowser->append("scoket 状态:ListeningState");
            break;
        case QAbstractSocket::BoundState:
            textBrowser->append("scoket 状态:BoundState");
            break;
        default:
            break;
    }
}

效果

image

组播

代码

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QUdpSocket>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QTextBrowser>
#include <QLabel>
#include <QComboBox>
#include <QSpinBox>
#include <QHostInfo>
#include <QLineEdit>
#include <QNetworkInterface>
#include <QDebug>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    /* Udp 通信套接字 */
    QUdpSocket *udpSocket;
   
    /* 按钮 */
    QPushButton *pushButton[4];
   
    /* 标签文本 */
    QLabel *label[3];
   
    /* 水平容器 */
    QWidget *hWidget[3];
   
    /* 水平布局 */
    QHBoxLayout *hBoxLayout[3];
   
    /* 垂直容器 */
    QWidget *vWidget;
   
    /* 垂直布局 */
    QVBoxLayout *vBoxLayout;
   
    /* 文本浏览框 */
    QTextBrowser *textBrowser;
   
    /* 用于显示本地 ip */
    QComboBox *comboBox[2];
   
    /* 用于选择端口 */
    QSpinBox *spinBox;
   
    /* 文本输入框 */
    QLineEdit *lineEdit;
   
    /* 存储本地的 ip 列表地址 */
    QList<QHostAddress> IPlist;
   
    /* 获取本地的所有 ip */
    void getLocalHostIP();
private slots:
    /* 加入组播 */
    void joinGroup();
    
    /* 退出组播 */
    void leaveGroup();
    
    /* 清除文本框时的内容 */
    void clearTextBrowser();
    
    /* 接收到消息 */
    void receiveMessages();
    
    /* 组播消息 */
    void sendMessages();
    
    /* 连接状态改变槽函数 */
    void socketStateChange(QAbstractSocket::SocketState);
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    /* 设置主窗体的位置与大小 */
    this->setGeometry(0, 0, 800, 480);

    /* udp 套接字 */
    udpSocket = new QUdpSocket(this);

    /* 参数 1 是设置 IP_MULTICAST_TTL 套接字选项允许应用程序主要限制数据包在
    Internet 中的生存时间,
    * 并防止其无限期地循环,数据报跨一个路由会减一,默认值为 1,表示多播仅适用于
    本地子网。*/
    udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);

    /* 加入组播按钮 */
    pushButton[0] = new QPushButton();
    /* 退出组播按钮 */
    pushButton[1] = new QPushButton();
    /* 清空聊天文本按钮 */
    pushButton[2] = new QPushButton();
    /* 组播消息按钮 */
    pushButton[3] = new QPushButton();

    /* 水平布局一 */
    hBoxLayout[0] = new QHBoxLayout();
    /* 水平布局二 */
    hBoxLayout[1] = new QHBoxLayout();
    /* 水平布局三 */
    hBoxLayout[2] = new QHBoxLayout();
    /* 水平布局四 */
    hBoxLayout[3] = new QHBoxLayout();

    /* 水平容器一 */
    hWidget[0] = new QWidget();
    /* 水平容器二 */
    hWidget[1] = new QWidget();
    /* 水平容器三 */
    hWidget[2] = new QWidget();


    vWidget = new QWidget();
    vBoxLayout = new QVBoxLayout();

    /* 标签实例化 */
    label[0] = new QLabel();
    label[1] = new QLabel();
    label[2] = new QLabel();

    lineEdit = new QLineEdit();
    comboBox[0] = new QComboBox();
    comboBox[1] = new QComboBox();
    spinBox = new QSpinBox();
    textBrowser = new QTextBrowser();

    label[0]->setText("本地 IP 地址:");
    label[1]->setText("组播地址:");
    label[2]->setText("组播端口:");

    /* 设置标签根据文本文字大小自适应大小 */
    label[0]->setSizePolicy(QSizePolicy::Fixed,
    QSizePolicy::Fixed);
    label[1]->setSizePolicy(QSizePolicy::Fixed,
    QSizePolicy::Fixed);
    label[2]->setSizePolicy(QSizePolicy::Fixed,
    QSizePolicy::Fixed);

    /* 设置端口号的范围,注意不要与主机的已使用的端口号冲突 */
    spinBox->setRange(10000, 99999);

    pushButton[0]->setText("加入组播");
    pushButton[1]->setText("退出组播");
    pushButton[2]->setText("清空文本");
    pushButton[3]->setText("组播消息");

    /* 设置停止监听状态不可用 */
    pushButton[1]->setEnabled(false);

    /* 设置输入框默认的文本 */
    lineEdit->setText("您好!");

    /* 默认添加范围内的一个组播地址 */
    comboBox[1]->addItem("239.255.255.1");

    /* 设置可编辑,用户可自行修改此地址 */
    comboBox[1]->setEditable(true);

    /* 水平布局一添加内容 */
    hBoxLayout[0]->addWidget(pushButton[0]);
    hBoxLayout[0]->addWidget(pushButton[1]);
    hBoxLayout[0]->addWidget(pushButton[2]);

    /* 设置水平容器的布局为水平布局一 */
    hWidget[0]->setLayout(hBoxLayout[0]);

    hBoxLayout[1]->addWidget(label[0]);
    hBoxLayout[1]->addWidget(comboBox[0]);
    hBoxLayout[1]->addWidget(label[1]);
    hBoxLayout[1]->addWidget(comboBox[1]);
    hBoxLayout[1]->addWidget(label[2]);
    hBoxLayout[1]->addWidget(spinBox);

    /* 设置水平容器的布局为水平布局二 */
    hWidget[1]->setLayout(hBoxLayout[1]);

    /* 水平布局三添加内容 */
    hBoxLayout[2]->addWidget(lineEdit);
    hBoxLayout[2]->addWidget(pushButton[3]);

    /* 设置水平容器三的布局为水平布局一 */
    hWidget[2]->setLayout(hBoxLayout[2]);

    /* 垂直布局添加内容 */
    vBoxLayout->addWidget(textBrowser);
    vBoxLayout->addWidget(hWidget[1]);
    vBoxLayout->addWidget(hWidget[0]);
    vBoxLayout->addWidget(hWidget[2]);

    /* 设置垂直容器的布局为垂直布局 */
    vWidget->setLayout(vBoxLayout);

    /* 居中显示 */
    setCentralWidget(vWidget);

    /* 获取本地 ip */
    getLocalHostIP();

    /* 信号槽连接 */
    connect(pushButton[0], SIGNAL(clicked()),
            this, SLOT(joinGroup()));
    connect(pushButton[1], SIGNAL(clicked()),
            this, SLOT(leaveGroup()));
    connect(pushButton[2], SIGNAL(clicked()),
            this, SLOT(clearTextBrowser()));
    connect(pushButton[3], SIGNAL(clicked()),
            this, SLOT(sendMessages()));
    connect(udpSocket, SIGNAL(readyRead()),
            this, SLOT(receiveMessages()));
    connect(udpSocket,
            SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,
            SLOT(socketStateChange(QAbstractSocket::SocketState)));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::joinGroup()
{
    /* 获取端口 */
    quint16 port = spinBox->value();
    /* 获取组播地址 */
    QHostAddress groupAddr = QHostAddress(comboBox[1]->currentText());

    /* 绑定端口需要在 socket 的状态为 UnconnectedState */
    if (udpSocket->state() != QAbstractSocket::UnconnectedState)
    udpSocket->close();

    /* 加入组播前必须先绑定端口 */
    if (udpSocket->bind(QHostAddress::AnyIPv4,
    port, QUdpSocket::ShareAddress)) {

        /* 加入组播组,返回结果给 ok 变量 */
        bool ok = udpSocket->joinMulticastGroup(groupAddr);

        textBrowser->append(ok ? "加入组播成功" : "加入组播失败");

        textBrowser->append("组播地址 IP:"
                            + comboBox[1]->currentText());

        textBrowser->append("绑定端口:"
                            + QString::number(port));

        /* 设置界面中的元素的可用状态 */
        pushButton[0]->setEnabled(false);
        pushButton[1]->setEnabled(true);
        comboBox[1]->setEnabled(false);
        spinBox->setEnabled(false);
    }
}

void MainWindow::leaveGroup()
{
    /* 获取组播地址 */
    QHostAddress groupAddr = QHostAddress(comboBox[1]->currentText());

    /* 退出组播 */
    udpSocket->leaveMulticastGroup(groupAddr);

    /* 解绑,不再监听 */
    udpSocket->abort();

    /* 设置界面中的元素的可用状态 */
    pushButton[0]->setEnabled(true);
    pushButton[1]->setEnabled(false);
    comboBox[1]->setEnabled(true);
    spinBox->setEnabled(true);
}

/* 获取本地 IP */
void MainWindow::getLocalHostIP()
{
    // /* 获取主机的名称 */
    // QString hostName = QHostInfo::localHostName();

    // /* 主机的信息 */
    // QHostInfo hostInfo = QHostInfo::fromName(hostName);

    // /* ip 列表,addresses 返回 ip 地址列表,注意主机应能从路由器获取到
    // * IP,否则可能返回空的列表(ubuntu 用此方法只能获取到环回 IP) */
    // IPlist = hostInfo.addresses();
    // qDebug()<<IPlist<<endl;

    // /* 遍历 IPlist */
    // foreach (QHostAddress ip, IPlist) {
    // if (ip.protocol() == QAbstractSocket::IPv4Protocol)
    // comboBox->addItem(ip.toString());
    // }

    /* 获取所有的网络接口,
    * QNetworkInterface 类提供主机的 IP 地址和网络接口的列表 */
    QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();

    /* 遍历 list */
    foreach (QNetworkInterface interface, list) {
        /* QNetworkAddressEntry 类存储 IP 地址子网掩码和广播地址 */
        QList<QNetworkAddressEntry> entryList
        = interface.addressEntries();

        /* 遍历 entryList */
        foreach (QNetworkAddressEntry entry, entryList) {
            /* 过滤 IPv6 地址,只留下 IPv4 */
            if (entry.ip().protocol() ==
                QAbstractSocket::IPv4Protocol &&
                ! entry.ip().isLoopback()) {
                comboBox[0]->addItem(entry.ip().toString());
                /* 添加到 IP 列表中 */
                IPlist<<entry.ip();
            }
        }
    }
}

/* 清除文本浏览框里的内容 */
void MainWindow::clearTextBrowser()
{
    /* 清除文本浏览器的内容 */
    textBrowser->clear();
}

/* 客户端接收消息 */
void MainWindow::receiveMessages()
{
    /* 局部变量,用于获取发送者的 IP 和端口 */
    QHostAddress peerAddr;
    quint16 peerPort;

    /* 如果有数据已经准备好 */
    while (udpSocket->hasPendingDatagrams()) {
        /* udpSocket 发送的数据报是 QByteArray 类型的字节数组 */
        QByteArray datagram;

        /* 重新定义数组的大小 */
        datagram.resize(udpSocket->pendingDatagramSize());

        /* 读取数据,并获取发送方的 IP 地址和端口 */
        udpSocket->readDatagram(datagram.data(),
                                datagram.size(),
                                &peerAddr,
                                &peerPort);
        /* 转为字符串 */
        QString str = datagram.data();

        /* 显示信息到文本浏览框窗口 */
        textBrowser->append("接收来自"
                            + peerAddr.toString()
                            + ":"
                            + QString::number(peerPort)
                            + str);
    }
}

/* 客户端发送消息 */
void MainWindow::sendMessages()
{
    /* 文本浏览框显示发送的信息 */
    textBrowser->append("发送:" + lineEdit->text());

    /* 要发送的信息,转为 QByteArray 类型字节数组,数据一般少于 512 个字节 */
    QByteArray data = lineEdit->text().toUtf8();

    /* 要发送的目标 Ip 地址 */
    QHostAddress peerAddr = IPlist[comboBox[1]->currentIndex()];

    /* 要发送的目标端口号 */
    quint16 peerPort = spinBox->value();

    /* 发送消息 */
    udpSocket->writeDatagram(data, peerAddr, peerPort);
}


/* socket 状态改变 */
void MainWindow::socketStateChange(QAbstractSocket::SocketState state)
{
    switch (state) {
        case QAbstractSocket::UnconnectedState:
            textBrowser->append("scoket 状态:UnconnectedState");
            break;
        case QAbstractSocket::ConnectedState:
            textBrowser->append("scoket 状态:ConnectedState");
            break;
        case QAbstractSocket::ConnectingState:
            textBrowser->append("scoket 状态:ConnectingState");
            break;
        case QAbstractSocket::HostLookupState:
            textBrowser->append("scoket 状态:HostLookupState");
            break;
        case QAbstractSocket::ClosingState:
            textBrowser->append("scoket 状态:ClosingState");
            break;
        case QAbstractSocket::ListeningState:
            textBrowser->append("scoket 状态:ListeningState");
            break;
        case QAbstractSocket::BoundState:
            textBrowser->append("scoket 状态:BoundState");
            break;
        default:
            break;
    }
}

效果

image

这篇关于网络编程——UDP通信的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!