2013-01-03 2 views
1

SSL 서버를 만들려고 QTcpServer를 서브 클래스 화하고 incomingConnection()을 재정의합니다. 여기에서 QSslSocket을 만들고 설명자를 설정하고 QSslSocket::startServerEncryption을 호출합니다. 이 시점에서 QSslSocket::encrypted() 신호가 방출 될 때까지 기다릴 필요가 있습니다. 그 후에야 내 서버가 newConnection() 신호를 방출해야합니다. 클라이언트 코드는 QTcpSocket을 사용하고 있다고 생각하지만 사실 안전한 소켓을 사용하게 될 것입니다. 항상newConnection()incomingConnection()를 호출 한 후 방출 QTcpServerQTcpServer를 서브 클래스화할 때 newConnection() 신호가 출력되는 것을 어떻게 지연시킬 수 있습니까?

그러나 은 (내가 the source of QTcpServer에서 보았다) :

그래서 내 질문은
void QTcpServerPrivate::readNotification() 
{ 
    // ......... 
     q->incomingConnection(descriptor); 
     QPointer<QTcpServer> that = q; 
     emit q->newConnection(); 
    // ......... 
} 

, 난 때까지 , 나는 newConnection() 발광에서 QTcpServer을 방지 할 수있는 방법이 나 자신을 방출 할 준비가 되셨습니까?

I이 원하는 그 이유는 나는 그것이 QTcpServer으로 정확하게 행동해야한다, 그래서 내 클래스는, 그것을 사용하고 인식하지 못하는 코드에 의해, QTcpServer의 드롭 인 교체로 사용할 수 있도록하려는 것입니다 :

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

SslServer 클래스 내 코드는 현재 이것이다 : 당신이 일반적으로 구현할 수 없기 때문에, 당신은 아마, Qt를의 실제 소스를 편집해야합니다

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; 
    } 
} 

답변

2

다음은이 경우 사용할 수있는 아이디어입니다. QTcpServer 서브 클래스에서 newConnection 신호를 재정의하십시오.

이렇게하면 서버 인스턴스에 연결된 객체는 신호의 QTcpServer의 "버전"을받지 못하며 하위 클래스에서 직접 방사하는 객체 만 수신합니다.

여기 개념의 증거 : 클래스 AQTcpServer입니다 foo는 "납치"하려는 신호, bar 당신이 접촉 할 필요가 없습니다 QTcpServer의 신호의 또 다른 (가상)입니다.

클래스 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는 잠재 고객 인 A 예를 들어 것 정확히 같은 B 인스턴스에서 신호/슬롯을 연결합니다.

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

... 그리고 아무것도 :

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; 
     } 
}; 

여기는 A C을 구성에서 출력합니다. Aemit foo(1)C의 슬롯 foo에 연결되어 있지 않으므로 C에 도착하지 않습니다. Aemit bar(1)은 예상대로 작동했지만 신호는 변경되지 않았습니다.

이 설정으로 수업 준비가 완료되면 newConnection을 내보낼 수 있습니다. QTcpServer 님의 신호 버전이 사용자의 개체에 수신되지 않습니다.

1

교체의 진정한 드롭 할 수 어떤 Private 클래스 호출.

은 그냥 자신의 슬롯 handleNewConnectionnewConnection를 연결

당신이 교체 하나를 사용하여 하나의, 그리고 당신이 newConnection 신호에 연결 클래스를 제어하면 .... 보안 연결이 준비되면 myNewConnection을 내고 newConnection에 연결된 요소에 연결하십시오.

편집 : 파고의 조금 후 , 내가 신호를 다시 연결의 옵션을 발견

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

기본적으로, 당신은 QObject::connect을 구현할를, 그리고 당신은 연결을 추적하고 그들에게 처리 당신이 필요로하는 방식. 따라서이 경우 신호 newConnection의 모든 연결 목록을 유지하고 목록에 보관하면 연결을 끊을 때 다시 연결할 수 있습니다. 재 구현이 끝나면 QObject::connect으로 전화하십시오.

이 경로를 사용할 때 또 다른 옵션은 연결을 다시 라우팅하는 것입니다. newConnection에 연결이 요청되면 myNewConnection으로 이동하십시오.

희망이 있습니다.

+1

신호를 분리하고 나중에 다시 연결하면 어떨까요? 가능한가? 그리고 아니오, 확실히 Qt 소스를 다시 쓸 필요가 없습니다. – sashoalm

+0

시도해 볼 수 있습니다 : ['QObject :: disconnect'] (http://qt-project.org/doc/qt-4.8/qobject.html#disconnect). 나는 그것을 잘 알기에 충분하지 못했다. – phyatt

+1

문제는 나중에 신호를 다시 연결해야하므로 신호에 대한 수신기 목록을 어떻게 든 가져와야합니다. 저는 이것을 새로운 질문으로 게시하고 있습니다 - http://stackoverflow.com/q/14144415/492336. – sashoalm

1

더러운 해킹은 QTcpServer의 신호를 매우 간략하게 차단하는 것입니다. SslServer::incomingConnection()에서 돌아온 직후에 newConnection()이 방출 될 것이라는 사실을 알고 계시다면 반환하기 바로 전에 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() 사이 emited 할 수있는 모든 신호를 잃을 것입니다. 내가 말했듯이, 그것은 더러운 해킹입니다.