Qt QUdpSocket:readyRead()信号和相应的插槽不能正常工作

时间:2014-01-20 01:26:00

标签: c++ qt sockets qudpsocket

我有问题要找到为什么我的简短QUdpSocket示例不起作用。我计划在端口2007上只使用一个UDP套接字读取和写入192.168.2.66的嵌入式设备。设备将始终在端口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);
}
//------------------------------------------------------------------------

我使用Qt 5语法进行connect(),m_strHost值为“192.168.2.66”,m_wPort为2007

我的Write方法非常简单(添加#if 0里面的部分以查看套接字是否收到任何数据)

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);
}
//------------------------------------------------------------------------

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

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

我不明白有什么问题。我发现一些帖子说在Qt中只使用一个UDP套接字是不可能读写的(Qt使用BSD套接字所以它应该是可能的)但我的例子看起来像建议的那样解决方案所以我真的不明白什么是无效的。

1 个答案:

答案 0 :(得分:2)

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

要在QUdpSocket中建立Rx直接通信,你应该使用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”是包含我的QUdpSocketudpSocket的类是QUdpSocket指针。然后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事件”)并将数据粘贴到QByteArray并在其他地方发出(你显然没有要做!)。

这就是你需要做的连接。然后发送非常简单,你只需要调用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()个事件。