首页 > 解决方案 > 如何从 QUdpSocket 检测“端口不可达”情况?

问题描述

我正在尝试使用QUdpSocket将一些数据发送到明确定义的主机:端口目的地。当目标端口没有被监听时(例如客户端没有运行),ICMP 消息会显示“端口不可达”。

我想在我的程序中检测到这种情况并在它发生时采取行动。我在某处读到,如果我直接“连接”到主机而不是仅仅对我的数据报进行“即发即弃”,那么应用程序应该会收到这些 ICMP 通知。但以下代码似乎没有出现任何错误。

#include <QTimer>
#include <QString>
#include <QUdpSocket>
#include <QCoreApplication>

class DataSender : public QObject
{
public:
    DataSender(const QString& host, quint16 port);
    void send(const char* data, unsigned size);

private:
    void onSocketError(QUdpSocket::SocketError error);

private:
    QUdpSocket socket;
};

DataSender::DataSender(const QString& host, const quint16 port)
{
    connect(&socket, &QUdpSocket::connected, this, []{qDebug() << "connected";});
    connect(&socket, &QUdpSocket::disconnected, this, []{qDebug() << "disconnected";});
    connect(&socket, &QUdpSocket::hostFound, this, []{qDebug() << "hostFound";});
    connect(&socket, qOverload<QUdpSocket::SocketError>(&QUdpSocket::error), this, &DataSender::onSocketError);
    socket.connectToHost(host, port, QIODevice::WriteOnly);
    qDebug() << "UDP server started";
}

void DataSender::send(const char*const data, const unsigned size)
{
    socket.write(data, size);
}

void DataSender::onSocketError(const QUdpSocket::SocketError)
{
    qDebug() << "UDP socket error:" << socket.errorString();
}

int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);

    DataSender sender("127.0.0.1", 33333);

    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, [&sender]{ sender.send("Test", 4); });
    timer.start(1000);

    return app.exec();
}

在输出中我只得到

hostFound
connected
UDP server started

同时,在运行这个测试时,我确实在 Wireshark 中看到了“Port unreachable”ICMP 消息。我如何才能真正接收和处理它们?

我发现在 Linux 套接字 API 中 write(2) 系统调用errno=ECONNREFUSED在这种情况下返回 -1。但是QUdpSocket我想获得一个跨平台的解决方案。我还发现 syscall-set在返回errno后似乎确实被保留了QUdpSocket::write(),所以我也许可以使用它,但这是特定于 Linux 的,而我的目标平台列表也包括 Windows。

标签: c++qtnetworkingudpicmp

解决方案


推荐阅读