首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在子类QTcpServer时,如何延迟发出newConnection()信号?

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

Stack Overflow用户
提问于 2013-01-03 17:11:41
回答 3查看 1.1K关注 0票数 1

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

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

代码语言:javascript
复制
void QTcpServerPrivate::readNotification()
{
    // .........
        q->incomingConnection(descriptor);
        QPointer<QTcpServer> that = q;
        emit q->newConnection();
    // .........
}

所以我的问题是,在我准备好自己发射QTcpServer newConnection()**,之前,有没有办法阻止发射?**

我想要这样做的原因是,我希望我的类能够作为QTcpServer的插入替代,由不知道它正在使用它的代码代替,所以它必须完全像QTcpServer那样运行:

代码语言:javascript
复制
QTcpServer* getServer(bool ssl)
{
    return ssl ? new SslServer : new QTcpServer;
}

我为SslServer类编写的代码当前如下:

代码语言:javascript
复制
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;
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-01-03 19:04:42

这里有一个可以在本例中工作的想法:在您的newConnection子类中重新定义QTcpServer信号。

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

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

代码语言:javascript
复制
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做任何事情。

代码语言:javascript
复制
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实例一样。

代码语言:javascript
复制
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的输出

代码语言:javascript
复制
B::doit       // this is /* 1 */
foo:  2 
bar:  2 
A::doit       // this is /* 2 */
bar:  1 

..。没别的事了。Aemit foo(1)没有连接到Cfoo插槽,它永远不会到达CAemit bar(1)按预期工作,这个信号是不动的。

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

票数 3
EN

Stack Overflow用户

发布于 2013-01-03 17:24:52

要真正减少替换,您可能需要编辑Qt的实际源,因为通常不能重新实现任何Private类调用。

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

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

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

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

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

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

希望这能有所帮助。

票数 1
EN

Stack Overflow用户

发布于 2013-01-03 22:07:14

一个肮脏的黑客将是非常简短地阻止来自QTcpServer的信号。因为您知道newConnection()将在您从SslServer::incomingConnection()返回后立即发出,所以在返回之前调用this->blockSignals(true);。这将阻止newConnection()调用连接到的任何时隙。

为了确保您收到后续信号,请尽快解除阻塞信号。我认为,当控制返回到事件循环时,可用的最早时间是正确的,因此QTimer::singleShot可以做到这一点。

代码语言:javascript
复制
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()之间合法发射的信号。就像我说的,这是个肮脏的黑客。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14143730

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档