繁体   English   中英

子类化QTcpServer时,如何延迟发出newConnection()信号?

[英]When subclassing QTcpServer, how can I delay emitting the newConnection() signal?

我想创建一个SSL服务器,所以我将QTcpServer子类化,并覆盖incomingConnection() ,在其中创建QSslSocket ,设置其描述符,并调用QSslSocket::startServerEncryption 此时我需要等待QSslSocket::encrypted()信号,并且只有在此之后我的服务器newConnection()发出newConnection()信号。 客户端代码会认为它使用的是QTcpSocket,但事实上它将使用安全套接字。

但是QTcpServer在调用incomingConnection() newConnection()之后总是发出 newConnection() (我查看了QTcpServer的源代码 ):

void QTcpServerPrivate::readNotification()
{
    // .........
        q->incomingConnection(descriptor);
        QPointer<QTcpServer> that = q;
        emit q->newConnection();
    // .........
}

所以我的问题是, 有没有办法阻止QTcpServer发出newConnection() ,直到我准备好自己发出它?

我想要这个的原因是我希望我的类能够被用作QTcpServer的替代品,通过不知道它正在使用它的代码,所以它必须像QTcpServer一样运行:

QTcpServer* getServer(bool ssl)
{
    return ssl ? new SslServer : new QTcpServer;
}

我的SslServer类代码目前是这样的:

void SslServer::ready()
{
    QSslSocket *socket = (QSslSocket *) sender();
    addPendingConnection(socket);
    emit newConnection();
}

void SslServer::incomingConnection(int socketDescriptor)
{
    QSslSocket *serverSocket = new QSslSocket;
    if (serverSocket->setSocketDescriptor(socketDescriptor)) {
        connect(serverSocket, SIGNAL(encrypted()), this, SLOT(ready()));
        serverSocket->startServerEncryption();
    } else {
        delete serverSocket;
    }
}

这是一个可以在这种情况下工作的想法:重新定义QTcpServer子类中的newConnection信号。

如果这样做,与服务器实例连接的对象将不会收到QTcpServer的信号“版本”,只接收您直接从子类发出的信号。

这是一个概念验证: A类是QTcpServerfoo是你试图“劫持”的信号, bar只是你不需要触摸的另一个(假设的) QTcpServer信号。

class A: public QObject
{
    Q_OBJECT
    public:
        A() {};
        virtual void doit() {
            qDebug() << "A::doit";
            emit foo(1);
            emit bar(1);
        }
    signals:
        void foo(int);
        void bar(int);
};

B类是您的子类。 请注意,它重新定义了信号foo ,但没有做任何事情来bar

class B: public A
{
    Q_OBJECT
    public:
        B() {};
        virtual void doit() {
            qDebug() << "B::doit";
            emit foo(2);
            emit bar(2);
        }
    signals:
        void foo(int);
};

C类是一个潜在的客户端,它从B实例连接信号/槽,就像它对A实例一样。

class C: public QObject
{
    Q_OBJECT
    public:
        C() {
            B *b = new B;
            connect(b, SIGNAL(foo(int)), this, SLOT(foo(int)));
            connect(b, SIGNAL(bar(int)), this, SLOT(bar(int)));
            /* 1 */
            b->doit();
            /* 2 */
            b->A::doit(); // call parent class's function
        };
    public slots:
        void foo(int i) {
            qDebug() << "foo: " << i;
        }
        void bar(int i) {
            qDebug() << "bar: " << i;
        }
};

这是构造C的输出:

B::doit       // this is /* 1 */
foo:  2 
bar:  2 
A::doit       // this is /* 2 */
bar:  1 

......别无其他。 Aemit foo(1)不连接到Cfoo槽,它永远不会到达C A emit bar(1)按预期工作,该信号未受影响。

使用该设置,您可以在类准备就绪时发出newConnection ,用户的对象将不会接收QTcpServer的信号版本。

要成为真正的替代品,您可能需要编辑Qt的实际来源,因为您通常无法重新实现任何Private类调用。

如果您是唯一一个使用替换的人,并且您控制连接到newConnection信号的类...

只需将newConnection连接到您自己的插槽handleNewConnection 当安全连接准备就绪时,发出myNewConnection并将其连接到已连接到newConnection的元素。

编辑:经过一番挖掘后,我找到了重新连接信号的选项:

http://qt-project.org/forums/viewthread/6820

基本上,您重新实现QObject::connect ,然后跟踪连接并按照您需要的方式处理它们。 因此,在这种情况下,您将保留信号newConnection的所有连接的列表并将其保存在列表中,因此当您断开连接时,您可以重新连接它。 务必在重新实现结束时调用QObject::connect

走这条路线的另一个选择就是去重新路由那里的连接。 当从newConnection请求连接时,将其移动到myNewConnection

希望有所帮助。

肮脏的黑客将非常短暂地阻止来自QTcpServer的信号。 既然你知道newConnection()将发射你返回后立即SslServer::incomingConnection()调用this->blockSignals(true); 就在你回来之前。 这将阻止newConnection()调用它所连接的任何插槽。

为确保您收到后续信号,请尽快取消阻止信号。 我认为当控制回到事件循环时,可用的最早时间是正确的,所以QTimer :: singleShot可以做到这一点。

void SslServer::incomingConnection(int socketDescriptor)
{
    QSslSocket *serverSocket = new QSslSocket;
    if (serverSocket->setSocketDescriptor(socketDescriptor)) {
        connect(serverSocket, SIGNAL(encrypted()), this, SLOT(ready()));
        serverSocket->startServerEncryption();
    } else {
        delete serverSocket;
    }

    this -> blockSignals(true);
    QTimer::singleShot(0, this, SLOT(unblockSignals());
}

void SslServer::unblockSignals()
{
    this->blockSignals(false);
}

这样做的缺点是你将失去在incomingConnection()unblockSignals()之间合法发出的每一个信号。 就像我说的那样,这是一个肮脏的黑客。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM