精华内容
下载资源
问答
  • QUdpSocket

    2020-12-29 23:01:45
    前言 我们经常使用 “ping” 命令来测试两台主机之间 TCP/IP 通信是否正常, 其实 “ping” 命令的原理就是向对方主机发送 UDP 数据包,然后对方主机确认收到数据包, 如果数据包是否到达的...QUdpSocket> #include

    前言

    我们经常使用 “ping” 命令来测试两台主机之间 TCP/IP 通信是否正常, 其实 “ping” 命令的原理就是向对方主机发送 UDP 数据包,然后对方主机确认收到数据包, 如果数据包是否到达的消息及时反馈回来,那么网络就是通的。

    准备工作

    首先,要使用 Qt 的网络模块需要在 pro 中加上 network(如果是 VS IDE 就在模块选择里勾选上 network):

    QT += network
    

    引入相关类的头文件:

    #include <QUdpSocket>
    #include <QHostAddress>
    #include <QNetworkDatagram>
    

    Qt UDP 的操作流程:
    在这里插入图片描述

    QUdpSocket的接口

    QUdpSocket 是 QAbstractSocket 的子类,用于发送和接收 UDP 数据报。

    可以使用 bind() 显式的绑定地址和端口。参数中的地址可以使用 QHostAddress::Any 绑定任意地址,IPv4 等效于 “0.0.0.0” , IPv6 等效于 “::”;而 BindMode 一般可以设置 ShareAddress(允许其他服务绑定到相同的地址和端口) 和 DontShareAddress(不允许其他服务重新绑定),Windows 上默认等效于 ShareAddress。

    bool QAbstractSocket::bind(const QHostAddress &address, quint16 port = 0, QAbstractSocket::BindMode mode = DefaultForPlatform)
    bool QAbstractSocket::bind(quint16 port = 0, QAbstractSocket::BindMode mode = DefaultForPlatform)
    

    绑定后,只要 UDP 数据报到达指定的地址和端口,就会触发 readyRead() 信号,此时可在槽函数中读取数据:

    void QIODevice::readyRead()
    

    可通过 hasPendingDatagrams() 判断是否有可读数据,通过 pendingDatagramSize() 判断数据长度。

    对于数据报的读写依然是使用 read/write 相关接口:

    qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr)
    QNetworkDatagram QUdpSocket::receiveDatagram(qint64 maxSize = -1)
    qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port)
    qint64 QUdpSocket::writeDatagram(const QNetworkDatagram &datagram)
    qint64 QUdpSocket::writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port)
    

    对于单播,可以直接指定目标地址和端口发送:

    const QString address_text = "127.0.0.1";
    const QHostAddress address = QHostAddress(address_text);
    const unsigned short port = 12345;
    udpSocket->writeDatagram(QNetworkDatagram(send_data,address,port));
    

    对于广播,需要发送到广播地址 “255.255.255.255”,即使用 QHostAddress::Broadcast:

    udpSocket->writeDatagram(QNetworkDatagram(send_data,QHostAddress::Broadcast,port));
    

    对于组播,需要发送到指定的组播地址,不过要对方加入了这个组播(使用 joinMulticastGroup 和 leaveMulticastGroup 加入/退出组播):

    //组播ip必须是D类ip
    //D类IP段 224.0.0.0 到 239.255.255.255
    //且组播地址不能是224.0.0.1
    udpSocket->bind(QHostAddress::AnyIPv4,port); //根据Qt示例,组播的话IPv4和v6分开的
    udpSocket->joinMulticastGroup(address); //QHostAddress("224.0.0.2")
     
    udpSocket->writeDatagram(QNetworkDatagram(send_data,address,port)); //QHostAddress("224.0.0.2")
    

    操作完之后,调用相关接口关闭和释放:

    void QAbstractSocket::disconnectFromHost()
    void QAbstractSocket::close()
    void QAbstractSocket::abort()
    

    其中, abort 调用了 close, close 调用了 disconnectFromHost。 abort 立即关闭套接字,并丢弃写缓冲区中的所有待处理数据。close 关闭套接字的 IO,以及套接字的连接。

    QUdpSocket对象实例化

    QUdpSocket* m_udpSocket;
    m_udpSocket = new QUdpSocket(this);
    

    设置套接字选项

    void setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value)
    //Multicast路由层次,1表示只在同一局域网内
    //组播TTL: 生存时间,每跨1个路由会减1,多播无法跨过大多数路由所以为1
    //默认值是1,表示数据包只能在本地的子网中传送。
    m_udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 1);
    

    QAbstractSocket::MulticastTtlOption:设置多播,即将此设置为整数可以设置IP_MULTICAST_TTL(对于多播数据报为TTL)套接字选项。后面的value就是那个整数,即为TTL值,范围为0~255之间的任何值。

    QAbstractSocket::MulticastLoopbackOption:将value设置为1以启用IP_MULTICAST_LOOP(组播回环)套接字选项。即IP_MULTICAST_LOOP用于控制数据是否回送到本地的回环接口,0则禁用。

    UDP信号触发
    每当QAbstractSocket的状态更改时,都会发出此信号。 socketState参数是新状态。

    void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState)
    connect(m_udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    

    UDP通信的时候通过stateChanged信号来触发,通过对应的槽函数来触发。

    QAbstractSocket::SocketState:套接字的连接状态
    UnconnectedState:表示套接字没有连接,对应的默认值是0
    ConnectingState:套接字正在执行主机名查找,对应的值是1
    ConnectingState:套接字已开始建立连接。对应的值是2
    ConnectedState:连接处于建立状态,对应值是3
    BoundState:套接字绑定到地址和端口。对应值是4
    ListeningState:监听状态,仅内部使用,对应值是5
    ClosingState:套接字即将关闭(数据可能仍在等待写入)。对应值是6

    void ExMulticast::onSocketStateChange(QAbstractSocket::SocketState socketState)
    {
        switch (socketState) {
        case QAbstractSocket::UnconnectedState:
            m_labSocketState->setText("socket状态:UnconnectedState");
            break;
        case QAbstractSocket::HostLookupState:
            m_labSocketState->setText("socket状态:HostLookupState");
            break;
        case QAbstractSocket::ConnectingState:
            m_labSocketState->setText("socket状态:ConnectingState");
            break;
        case QAbstractSocket::ConnectedState:
            m_labSocketState->setText("socket状态:ConnectedState");
            break;
        case QAbstractSocket::BoundState:
            m_labSocketState->setText("socket状态:BoundState");
            break;
        case QAbstractSocket::ClosingState:
            m_labSocketState->setText("socket状态:ClosingState");
            break;
        case QAbstractSocket::ListeningState:
            m_labSocketState->setText("socket状态:ListeningState");
            break;
        default:
            m_labSocketState->setText("socket状态:其他未知状态...");
            break;
        }
    }
    
    展开全文
  • 在QT中使用QUdpSocket时提示QUdpSocket::joinMulticastGroup() called on a QUdpSocket when not in QUdpSocket::BoundState 在网上查了所谓的解决办法都不管用,尝试什么将QUdpsocket::NotShareAddress改为...

    在QT中使用QUdpSocket时提示QUdpSocket::joinMulticastGroup() called on a QUdpSocket when not in QUdpSocket::BoundState

    在网上查了所谓的解决办法都不管用,尝试什么将QUdpsocket::NotShareAddress改为QUdpSocket::ShareAddress都不行,最后发现是因为自己在加入组播前没有绑定端口号导致的错误,然后总结出了下面两个可能出现该错误的原因



    原因

    我总结了两个可能出错的原因有两种(并非一定就是这两种错误):

    (1)绑定的协议不是ipv4协议,因为目前使用的还是ipv4;所以确保为:

     sock.bind(QHostAddress::AnyIPv4,端口号);
    

    (2)是否已经绑定端口,在未绑定端口的情况下是加入不了组播的;因此需要先绑定一个端口再去加入组播地址
    (个人感觉第二种出错的几率可能高一点,所以一定要检查代码是否已经绑定了端口再加入组播!!!)

    展开全文
  • QUdpSocket使用整理

    千次阅读 2017-07-23 10:06:39
    QUdpSocket使用

    效果图
    这里写图片描述

    服务端源码
    注意:在.pro中添加QT += network

    udpserver.h

    #ifndef UDPSERVER_H
    #define UDPSERVER_H
    
    #include <QDialog>
    #include <QLabel>
    #include <QLineEdit>
    #include <QPushButton>
    #include <QVBoxLayout>
    #include <QUdpSocket>
    #include <QTimer>
    
    class UdpServer : public QDialog
    {
        Q_OBJECT
    
    public:
        UdpServer(QWidget *parent = 0,Qt::WindowFlags f=0);
        ~UdpServer();
    public slots:
        void StartBtnClicked();//点击开始按钮
        void timeout();//一段时间后执行函数
    private:
        QLabel *TimerLabel;
        QLineEdit *TextLineEdit;//发送内容的lineedit
        QPushButton *StartBtn;//开始按钮
        QVBoxLayout *mainLayout;//布局
        int port;//端口号
        bool isStarted;//是否开始
        QUdpSocket *udpSocket;//udp
        QTimer *timer;//计时器
    };
    
    #endif // UDPSERVER_H
    

    udpserver.cpp

    #include "udpserver.h"
    #include <QHostAddress>
    
    UdpServer::UdpServer(QWidget *parent, Qt::WindowFlags f)
        : QDialog(parent,f)
    {
        setWindowTitle(tr("UDP Server"));
    
        TimerLabel = new QLabel(tr("计时器:"),this);
        TextLineEdit = new QLineEdit(this);
        StartBtn = new QPushButton(tr("开始"),this);
    
        mainLayout = new QVBoxLayout(this);
        mainLayout->addWidget(TimerLabel);
        mainLayout->addWidget(TextLineEdit);
        mainLayout->addWidget(StartBtn);
    
        connect(StartBtn,SIGNAL(clicked()),this,SLOT(StartBtnClicked()));
    
        port =5555;
        isStarted=false;
        udpSocket = new QUdpSocket(this);
        timer = new QTimer(this);
        connect(timer,SIGNAL(timeout()),this,SLOT(timeout()));
    }
    
    UdpServer::~UdpServer()
    {
    
    }
    
    void UdpServer::StartBtnClicked()
    {
        if(!isStarted)
        {
            StartBtn->setText(tr("停止"));
            timer->start(1000);//每1秒执行一次timeout()
            isStarted =true;
        }
        else
        {
            StartBtn->setText(tr("开始"));
            isStarted = false;
            timer->stop();//停止
        }
    }
    
    void UdpServer::timeout()
    {
        QString msg = TextLineEdit->text();
        int length=0;
        if(msg=="")
        {
           return;
        }
        //通过udp写入传输数据
        if((length=udpSocket->writeDatagram(msg.toLatin1(),msg.length(),QHostAddress::Broadcast,port))!=msg.length())
        {
            return;
        }
    }
    

    客户端源码
    注意:在.pro中添加QT += network
    udpclient.h

    #ifndef UDPCLIENT_H
    #define UDPCLIENT_H
    
    #include <QDialog>
    #include <QVBoxLayout>
    #include <QTextEdit>
    #include <QPushButton>
    #include <QUdpSocket>
    
    class UdpClient : public QDialog
    {
        Q_OBJECT
    
    public:
        UdpClient(QWidget *parent = 0,Qt::WindowFlags f=0);
        ~UdpClient();    
    public slots:
        void CloseBtnClicked();//点击关闭按钮
        void dataReceived();//点击接受按钮
    private:
        QTextEdit *ReceiveTextEdit;//接受的内容
        QPushButton *CloseBtn;//关闭
        QVBoxLayout *mainLayout;//布局
        int port;//端口号
        QUdpSocket *udpSocket;//udp
    };
    
    #endif // UDPCLIENT_H
    

    udpclient.cpp

    #include "udpclient.h"
    #include <QMessageBox>
    #include <QHostAddress>
    
    UdpClient::UdpClient(QWidget *parent,Qt::WindowFlags f)
        : QDialog(parent,f)
    {
        setWindowTitle(tr("UDP Client"));
    
        ReceiveTextEdit = new QTextEdit(this);
        CloseBtn = new QPushButton(tr("Close"),this);
    
        mainLayout=new QVBoxLayout(this);
        mainLayout->addWidget(ReceiveTextEdit);
        mainLayout->addWidget(CloseBtn);
    
        connect(CloseBtn,SIGNAL(clicked()),this,SLOT(CloseBtnClicked()));
    
        port =5555;
    
        udpSocket = new QUdpSocket(this);
        connect(udpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
    
        bool result=udpSocket->bind(port);
        //当绑定失败时弹出提示
        if(!result)
        {
            QMessageBox::information(this,tr("error"),tr("udp socket create error!"));
            return;
        }
    }
    
    UdpClient::~UdpClient()
    {
    
    }
    
    void UdpClient::CloseBtnClicked()
    {
        close();
    }
    
    void UdpClient::dataReceived()
    {
        //通过udp接收数据
        while(udpSocket->hasPendingDatagrams())
        {
            QByteArray datagram;
            datagram.resize(udpSocket->pendingDatagramSize());
            //读取数据
            udpSocket->readDatagram(datagram.data(),datagram.size());
            QString msg=datagram.data();
            //向textdit中插入数据
            ReceiveTextEdit->insertPlainText(msg);
        }
    }
    
    展开全文
  • QUdpSocket 发送数据

    2020-07-20 20:58:55
    QUdpSocket m_udpSocket = new QUdpSocket(this); m_udpSocket->open(QUdpSocket::WriteOnly); m_udpSocket->bind(QHostAddress::LocalHost, 10000); 发送数据阶段: QByteArray testArray; testArray....

    问题:标准范式。

    方法:

    初始化阶段:

    QUdpSocket m_udpSocket = new QUdpSocket(this);

    m_udpSocket->open(QUdpSocket::WriteOnly);

    m_udpSocket->bind(QHostAddress::LocalHost, 10000);

    发送数据阶段:

    QByteArray testArray;

    testArray.clear();

    testArray.resize(8);

    ......

    m_UdpSocket->writeDatagram(testArray, QHostAddress::LocalHost, 12345);

    关闭连接阶段:

    if (m_udpSocket && m_udpSocket->isOpen())

    {

        m_udpSocket->close();

        delete m_udpSocket;

        m_udpSocket = nullptr;

    }

     

    展开全文
  • QUdpSocket Class

    2014-11-29 18:42:00
    翻译自:QT官网文档QUdpSocketQUdpSocket类提供一个UDP套接字。 Header: #include <QUdpSocket> qmake: QT += network Inherits: QAbstractSocket. 注意:这...
  • 初识QUdpsocket

    2015-10-29 15:48:52
    QUdpsocket最常用的用法:  先bind()到一个端口,然后调用writeDatagram()和readDatagram() 传输数据 在构造函数中:   socket=new QUdpSocket(this);  socket->bind(QHostAdd
  • QUdpSocket 接收数据

    2020-07-20 21:07:46
    m_udpSocket = new QUdpSocket(this); m_udpSocket->open(QUdpSocket::ReadOnly); m_udpSocket->bind(QHostAddress::Any, 12345); connect(m_udpSocket, SIGNAL(readyRead()), this, SLOT(handleReadyRead...
  • QUdpSocket实现聊天功能

    2017-12-18 17:31:15
    使用QUdpSocket实现类似微信聊天功能,输入完聊天信息按回车键发送聊天内容,文中使用到注册事件过滤器方法,socket通讯没有服务端与客户端之分的,本文为了区分演示用,控件上取名字时取了服务端和客户端。...
  • QT QUdpSocket 开发的局域网聊天工具 g
  • QUdpSocket 简单用法

    2017-03-31 23:00:00
    QUdpSocket是QAbstractSocket 的子类,它们都继承了QIODevice。所以可以用QUdpSocket进行发送接收数据。它和QTcpSocket最大的区别也就是,发送数据之前不需要建立连接。 以下简单例子,演示了用QUdpSocket如何实现...
  • QUdpSocket通信简易实例

    2021-06-03 15:11:58
    QUdpSocket通信简易实例 为了避免千篇一律,在本文中我只介绍我在使用QUdpSocket的使用体会,作为一个备忘录。 Udp通信和Tcp最大的不同就是基于无连接的通信,有点像是村里面的广播,我在广播里面说话,你不一定听到...
  • Qt UDP QUdpSocket多线程实例 movetothread
  • QUdpSocket *udpSocket = new QUdpSocket(this); QByteArray datagram = "UDP Datagram message "; udpSocket->writeDatagram(datagram, QHostAddress("169.254.254.11"), 36529); 接收端示例代码: void ...
  • 此代码实现了qt 通过qudpsocket传送结构体数据 并将接收的数据写入txt文件中 涉及网络与线程知识
  • 采用moveToThread方式实现QUdpSocket实现在新线程中接收数据 其中对于线程对象的资源释放经验证ok

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 633
精华内容 253
关键字:

QUdpSocket