2

我很难找到为什么我的简短QUdpSocket示例不起作用。我计划仅使用一个 UDP 套接字在 192.168.2.66 端口 2007 上读取和写入嵌入式设备。设备将始终在端口 2007 上回复发送者。我使用 UDP 终端软件测试了该设备,并按我说的那样工作。因此,我设计了一个简单的类来嵌入管理设备所需的功能:

class QUdp : public QObject
{
    // Q_OBJECT
public:
    explicit QUdp(QObject *parent = 0, const char *szHost = 0, uint16_t wPort = 0);
    ~QUdp();
    bool Open();
    int64_t Write(QByteArray &data);
    int64_t Write(QString strData);
private:
    QString m_strHost;
    uint16_t m_wPort;
    QUdpSocket *OUdp;
private slots:
    void received();
};

我想问题出在 Open 方法中:

bool QUdp::Open()
{
    QHostAddress OHost;
    connect(OUdp, &QUdpSocket::readyRead, this, &QUdp::received);
    bool zRet = OUdp->bind(QHostAddress::AnyIPv4, m_wPort, QUdpSocket::ShareAddress);
    OHost.setAddress(m_strHost);
    OUdp->connectToHost(OHost, m_wPort, QIODevice::ReadWrite);
    return(zRet);
}
//------------------------------------------------------------------------

我对 connect() 使用 Qt 5 语法,m_strHost值是“192.168.2.66”并且m_wPort是 2007

我的Write方法很简单(加了#if 0里面的部分,看socket有没有收到数据)

int64_t QUdp::Write(QString strData)
{
    QByteArray data(strData.toStdString().c_str(), strData.length());
    int64_t iCount = OUdp->write(data);
#if 0
    bool zRecved = OUdp->waitForReadyRead(3000);
    int64_t iRecvCount = OUdp->bytesAvailable();
#endif
    return(iCount);
}
//------------------------------------------------------------------------

这是我的测试接收()方法......我写它只是为了看看信号槽是否有效:

void QUdp::received()
{
    int64_t iRecvCount = OUdp->bytesAvailable();
}
//------------------------------------------------------------------------

我不明白出了什么问题。我发现一些帖子说在 Qt 中仅使用一个 UDP 套接字是不可能读写的(Qt 使用 BSD 套接字,所以应该是可能的)但是我的示例看起来是建议的解决方案,所以我真的不明白什么是行不通的。

4

1 回答 1

2

您可以在 Qt 中仅使用一个 UDP 套接字进行读写。我在 Windows 和 Linux 上都在 Qt5 中运行,所以不用担心 :)

要在其中建立 Rx 直接通信,QUdpSocket您应该真正使用 bind() 函数,如下所示:

// Rx connection: check we are not already bound
if (udpSocket->state() != udpSocket->BoundState)
{
    // Rx not in bound state, attempt to bind
    udpSocket->bind(address, port);
}

完成此操作后,您将能够检查udpSocket->state() == udpSocket->BoundState是否属实,然后您已成功“绑定”到此 ip/端口。现在,如果您的连接readready()正确,您就可以开始收听了。我没有使用您正在使用的这种连接语法,所以我不能说太多,但这里是我如何连接的示例:

connect(udpSocket, SIGNAL(readyRead()), this, SLOT(rxDataEvent()), Qt::QueuedConnection);

其中“this”是包含 myQUdpSocket并且udpSocketQUdpSocket指针的类。然后rxDataEvent定义如下:

void CIpComms::rxDataEvent(void)
{
    QByteArray rxData;
    QHostAddress sender;
    quint16 senderPort;

    while (udpSocket->hasPendingDatagrams())
    {
        // Resize and zero byte buffer so we can make way for the new data.
        rxData.fill(0, udpSocket->pendingDatagramSize());

        // Read data from the UDP buffer.
        udpSocket->readDatagram(rxData.data(),
                                rxData.size(),
                                &sender,
                                &senderPort);

        // Emit ipDataReceived Signal
        emit ipDataReceived(rxData);
    }
}

在这里,我们不断检查数据报,直到没有待处理的数据报(比做整个“bytesAvailable 事情”更容易一些)并将数据粘贴到 aQByteArray并将其发送到其他地方(您显然不必这样做!)。

这就是连接所需要做的一切。然后发送很容易,您只需调用writeDatagram(),还有其他选项,但这是迄今为止更容易使用:

if (-1 == udpSocket->writeDatagram(txData, address, port))
{
    // Data write failed, print out warning
    qWarning() << "Unable to write data to " << address.toString() << ":" << port << endl;
    return false;
}

我已经从我的工作代码中剪切并粘贴了很多内容(进行了一些编辑以使其保持简短,因此它应该为您提供一个起点。总之,我认为您出错的地方是您没有“绑定" 到 IP 地址/端口,因此不会监听它,也不会收到任何readReady()事件。

于 2014-01-20T08:06:21.317 回答