1

SSLサーバーを作成したいので、QTcpServerをサブクラス化し、オーバーライドしますincomingConnection()。ここで、を作成しQSslSocket、その記述子を設定して、を呼び出しますQSslSocket::startServerEncryption。この時点で、シグナルが発信されるのを待つ必要があります。QSslSocket::encrypted()その後、サーバーがnewConnection()シグナルを発信する必要があります。クライアントコードは、QTcpSocketを使用していると見なしますが、実際には安全なソケットを使用しています。

ただし、QTcpServerは newConnection()呼び出し後に常に出力しますincomingConnection()QTcpServerのソースを調べました)。

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

だから私の質問は、自分で放出する準備ができるまで、放出を防ぐ方法はありますか?QTcpServernewConnection()

これが必要な理由は、クラスがQTcpServerを使用していることを認識しないコードによって、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;
    }
}
4

3 に答える 3

2

この場合に有効なアイデアは次のとおりです。サブクラスでnewConnectionシグナルを再定義します。QTcpServer

これを行うと、サーバーのインスタンスに接続されたオブジェクトは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はあなたのサブクラスです。signal を再定義します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からのシグナル/スロットを接続します。BA

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 

... 何もありません。Aのはのスロットにemit foo(1)接続されていないため、 に到達することはありません。は期待どおりに機能し、その信号はそのままです。CfooCAemit bar(1)

そのセットアップではnewConnection、クラスの準備ができたときに発行できQTcpServerます。ユーザーのオブジェクトはシグナルのバージョンを受信しません。

于 2013-01-03T19:04:42.187 に答える
1

Private通常、クラス呼び出しを再実装することはできないため、実際の置き換えを行うには、おそらく Qt の実際のソースを編集する必要があります。

交換用のものを使用しているのがあなただけで、newConnection信号に接続するクラスを制御している場合...

newConnection自分のスロットに接続するだけhandleNewConnectionです。安全な接続の準備ができたら、myNewConnectionそれを発行して、接続されていたはずの要素に接続しnewConnectionます。

編集:少し掘り下げた後、信号を再接続するオプションを見つけました:

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

基本的に、 を再実装QObject::connectしてから、接続を追跡し、必要な方法で処理します。したがって、この場合、信号のすべての接続のリストをnewConnection保持し、それをリストに保持して、切断したときに再接続できるようにします。QObject::connect再実装の最後に必ず呼び出してください。

このルートに行くときの別のオプションは、そこに接続を再ルーティングすることです。から接続が要求されたら、newConnectionそこに移動しmyNewConnectionます。

それが役立つことを願っています。

于 2013-01-03T17:24:52.517 に答える
1

汚いハックは、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()。私が言ったように、それは汚いハックです。

于 2013-01-03T22:07:14.727 に答える