【问题标题】:QtNetwork: Why don't I detect incomming connections ? (incomingConnection() is never fired)QtNetwork:为什么我检测不到传入连接? (incomingConnection() 永远不会被解雇)
【发布时间】:2016-07-11 18:37:23
【问题描述】:

我坚持阅读关于线程 qt-networking 的教程(这里是:http://doc.qt.io/qt-5/qtnetwork-threadedfortuneserver-example.html),我做了一些小的改动并将其集成到我的主程序中。然而incomingConnection() 永远不会被执行,另一方面,客户端能够连接。因为我想使用 incomingConnection(),所以使用 SIGNAL(newConnection()) 已经过时了,但即使这样也行不通。

有人知道出了什么问题吗?

这里是我的.h

#include <QtNetwork>
#include <QTcpServer>
#include <QTcpSocket>
#include <QThread>

class WirelessNetThread: public Thread
{
    Q_OBJECT

public:
    WirelessNetThread(int socketDescriptor, QObject * parent);

    void run() Q_DECL_OVERRIDE;

signals:
    void error(QTcpSocket::SocketError socketError);

private:
    int socketDescriptor;
    QString text;
};

class WirelessNet : public QTcpServer
{
    Q_OBJECT

public:
    WirelessNet(QObject *parent = 0);

protected:
    void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;

};

还有.cpp

WirelessNetThread::WirelessNetThread(int socketDescriptor, QObject *parent):QThread(parent), socketDescriptor(socketDescriptor)
{
}

void WirelessNetThread::run()
{
    QTcpSocket tcpSocket;
    if ( !tcpSocket.setSocketDescriptor(socketDescriptor))
    {
        emit error(tcpSocket.error());
        return;
    }

    tcpSocket.disconnectFromHost();
    tcpSocket.waitForDisconnected();
}

WirelessNet::WirelessNet(QObject *parent): QTcpServer(0)
{
    listen(QHostAddress::Any, 5220);
    printf("is listening %d\n", this->isListening());
}

void WirelessNet::incomingConnection(qintptr socketDescriptor)
{
    qDebug() << "incomming \n";
    printf("incomming \n");
    WirelessNetThread *thread = new WirelessNetThread(socketDescriptor, this);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    thread->start();
}

这里是我的主程序的摘录,它是在哪里启动的(顺便说一句,如果我省略 moveToThread() 也没关系:

WirelessNet *wifi = new WirelessNet(this->parent());
wifi->moveToThread(this->thread());

如果我在初始化 wifi 之后添加这些行,即使这样也没有影响:

wifi = new WirelessNet(this->parent());
QEventLoop testLoop;
testLoop.exec();

换句话说,“incomming”永远不会被打印出来,所以我无法继续工作。有谁知道,这几乎是 1:1 的教程中的代码,这让我感到困惑。

【问题讨论】:

  • 这段代码来自教程?...你有链接吗? - 它要么很旧,要么写得很糟糕(Qt-wise)。我很难看到“incomingConnection()”是如何被调用的——是否有信号连接到它?但是在你深入这个之前......有很多关于继承线程和启动事件循环的混乱......所有这一切都不是必需的,并且使得遵循和维护非常混乱。我只是在这里发布了一个关于线程的答案:stackoverflow.com/questions/36201769/… - 看看 QThread 的用法
  • .. 为您提供标准 Qt 类之外的 4 行代码,以将其放入线程中。然后您的 WirelessNet 类中的所有代码都可以专注于“无线网络的东西”并且没有线程废话:)。我可以发布一个答案,说明我将如何实现你正在做的事情......但我仍然想念incomingConnection() 的调用方式......
  • @code_fodder 教程的链接在第一行中提到。我对incomingConnection() 有过同样的挣扎。 AFAIU 这个函数是一个被覆盖的函数(即一个虚函数),如果你从QThread 继承一个类,它具有与覆盖run() 函数类似的机制。不幸的是,我没有时间仔细观察
  • @code_fodder 我用另一个主题中提到的代码尝试了你的方法。我得到了从一个类到另一个类的信号/插槽响应,但是主要问题也没有改变。对incomingConnection()SIGNAL(newConnection()) 仍然没有反应
  • 啊,它是一个 TcpServer 覆盖函数,明白了。文档说这个函数(当没有被覆盖时)将发出 newConnection() 信号。我知道你说过你试图捕捉这个信号,但你是否在删除你自己的覆盖函数incomingConnection() 之后尝试这样做? (即使用connect(myTcpObj, SIGNAL(newConnection()), this (), SLOT(someSlotWithDebugInIt())); 之类的东西,我只问您的incomingConnection 有问题(看不到什么)来检查基础是否正常工作。

标签: c++ qt qthread qtcpsocket qtcpserver


【解决方案1】:

在您的主代码中:

WirelessNet *wifi = new WirelessNet(0); // 0 = assign no parent
QThread *wifiThread = new QThread;
wifi->moveToThread(wifiThread);
QObject::connect(wifiThread, SIGNAL(started()), wifi, SLOT(startWifi()));
// start() will start its own event loop, it will emit started(), therefore startWifi() slot will be called.
wifiThread->start();

然后是你的 WirelessNet 类头:

class WirelessNet : public QTcpServer
{
    Q_OBJECT

public:
    WirelessNet(QObject *parent = 0);

protected:
    void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;

public slots:
    void startWifi();
};

然后是您的 WirelessNet 类主体:

WirelessNet::WirelessNet(QObject *parent) : 
    QTcpServer(parent)
{
    // Do nothing much here because we want to initialise new stuff in our thread.
    // When this function runs we have not moved this to the new thread - or even started it.
}

void WirelessNet::incomingConnection(qintptr socketDescriptor)
{
    qDebug() << "incomming \n";
    printf("incomming \n");
    WirelessNetThread *thread = new WirelessNetThread(socketDescriptor, this);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    thread->start();
}

// Called when the thread has started
void WirelessNet::startWifi()
{
    // Anything done here is now safely within out new thread.
    listen(QHostAddress::Any, 5220);
    printf("is listening %d\n", this->isListening());
}

注意这是示例代码,我直接写到堆栈溢出它没有编译,所以可能有一些错误:) 有一些关键点,我已经评论过,你在哪里您最初的尝试可能出错了。

【讨论】:

  • 我真的不明白这种行为。现在WirelessNet() 的主体为空,startWifi() 如您的代码中所述。之前情况正好相反:startWifi() 几乎是空的,而构造函数 WirelessNet() 正在监听()。所以它现在可以工作了,我对此很满意,但你介意解释一下区别吗?
  • 这里的事情是(我试图在 cmets 中解释,但效果不佳)当您创建 wifi 对象时,会调用 c'tor(即 WirelessNet::WirelessNet())。您在此处创建的任何内容都将在创建 wifi 的线程中创建 - 即主线程。所以我删除了你的听电话。然后在你做 wifi.moveToThread(...);然后启动线程 (thread->start()) 您的对象 wifi 现在位于新线程中(并且线程也成为其父线程)。另外,因为我们将 QThread::started() 信号连接到 WirelessNet::startWifi() 插槽,所以当线程启动时,它会发出信号并...
  • ... startWifi() 被执行。请注意,在此函数/插槽中运行的任何内容现在都将在新线程中运行。所以我把你的 listen() 函数移到了这里。在那里,您的原始设置(如分配父母)的其他小问题再看我的 cmets,我只评论了发生有趣事情的地方。我不能说 100% 为什么在线程中移动监听有效,因为我不知道监听是做什么的......但如果它创建任何对象,它们将位于错误的位置(线程)!
  • 希望你会发现这段代码比继承和运行事件循环和其他东西更容易理解!还有一点需要注意:QThread 不是线程,它是线程控制器对象(它会在后台为您启动一个线程,以及事件循环)。
  • 非常感谢您的耐心和准确的答案,有时您正在寻找;,然后有时会发生这种情况,您阅读了一千遍仍然没有怀疑一件事;)
猜你喜欢
  • 2013-08-21
  • 2016-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-22
  • 2018-11-02
相关资源
最近更新 更多