2012-12-18 4 views
1

얼마 전 Qt (영어로 유감스럽게도)와 함께 작업 해 왔습니다. 저는 현재 QtNetwork와 협력 중입니다.QTcpSocket false QTcpServer에 연결

시스템과 같은 클라이언트 - 서버를 만들어야합니다. 기본 아이디어는 다음과 같습니다.

  • 둘 다 (클라이언트와 서버)의 IP가 변경 될 수 있습니다. 클라이언트의 구성 파일에 서버 IP를 저장할 수있는 방법이 없습니다. 따라서 서버는 어떤 식 으로든 IP를 공개해야하며 클라이언트는 연결할 서버 IP를 감지 할 수 있어야합니다.

  • 클라이언트는 서버없이 작업 할 수 있어야하며 서버를 연결 한 후에는 서버를 업데이트해야합니다.

  • 클라이언트와 서버가 동일한 WLAN 네트워크에서 실행되므로 인터넷을 통해 연결할 필요가 없습니다.

  • 이 새로운 시스템은 기존 시스템 (클라이언트 및 서버)을 대체하기위한 것입니다. 이전 서버는 UDP 브로드 캐스트 메시지 만 사용하여 클라이언트와 통신하므로 언젠가 메시지가 손실됩니다.

그래서 첫 번째 요점은 서버에 타이머를 구현 한 것입니다. 이 타이머는 매 X 시간마다 "서버에 연결"메시지와 함께 UDP를 통해 브로드 캐스트 메시지를 보냅니다. 이 메시지의 개념은 클라이언트가 이러한 메시지를 감지하고 연결할 서버 IP를 얻는 것입니다.

서버는 QTcpServer를 사용하여 클라이언트 연결을 감지하고 클라이언트마다 새로운 QTcpSocket을 저장하여 통신합니다.

클라이언트는 일단 서버 IP를 얻으면 TcpSocket을 사용하여 연결합니다.

간단합니다.

로컬 시스템 (서버와 일부 시스템이 동일한 시스템에서 실행중인 시스템)에서 시스템이 문제없이 작동합니다. 연결이 완료되고 통신이 작동합니다. 클라이언트와 서버 모두 gcc 4.7.2를 사용하여 Chakra Linux 64 비트에서 컴파일되었습니다. 시스템에 설치된 Qt 버전은 4.8.4입니다.

이제 Chakra Linux 64 비트에서 실행되는 서버와 Windows 7 (일부 32 비트와 다른 64 비트) 및 두 Windows 8 (32 비트 만)에서 실행되는 클라이언트로 시스템을 테스트했습니다. . Windows 버전의 클라이언트는 Windows 7 32 비트 (Qt 4.8.3 및 MingW 4.6.2)를 실행하는 가상 컴퓨터 (VirtualBox 4.2.4)에서 컴파일되었습니다. Windows 클라이언트는 모든 32 비트 컴파일 된 클라이언트 버전 (모든 32 비트 Windows 시스템과 64 비트 Windows 시스템)을 실행합니다.

클라이언트는 브로드 캐스트 메시지 (UDP, 포트 45454에서 작동 중임)를 검색하고 읽을 수 있으며 서버 IP (탐지 된 IP가 정확함)를 얻으면 연결을 시도합니다.

문제는 7 개의 클라이언트에서 한 번에 하나의 Windows 8 만 연결되었다는 것입니다. 모든 클라이언트가 연결을 시도하고 QTcpSocket이 모두 "연결된"신호를 내 보냅니다. 그러나 서버가 연결을 감지하지 못합니다.

가끔씩 하나 또는 두 개의 클라이언트를 연결할 수 있기 때문에 이는 완전히 임의적입니다. 다른 시간은 없습니다.

이 코드는 클라이언트 브로드 캐스트 초기화 용입니다.

broadcast_socket = new QUdpSocket(); 
server_connection = new QTcpSocket(); 
if (broadcast_socket->bind (QHostAddress::Any , cfg->networkControl()->udpPort()) == false) 
{ 
    cout << ">> NetworkManager: Error setting port " << cfg->networkControl()->udpPort() << " for UDP broadcast listen." << endl; 
} 
connect (broadcast_socket , SIGNAL (readyRead()) , this , SLOT (broadcastMessageReceived())); 
connect (server_connection , SIGNAL (readyRead()) , this , SLOT (serverMessageReceived())); 
connect (server_connection , SIGNAL (disconnected()) , this , SLOT (serverConnectionLost())); 
connect (server_connection , SIGNAL (connected()) , this , SLOT (serverConnected())); 

이 코드는 서버 브로드 캐스트 메시지를 수신 할 때 클라이언트의 코드입니다. 서버 측에

void NetworkManager::broadcastMessageReceived (void) 
{ 
    while (broadcast_socket->hasPendingDatagrams()) 
    { 
     QByteArray datagram; 
     QHostAddress sender_adress; 
     datagram.resize (broadcast_socket->pendingDatagramSize()); 
     broadcast_socket->readDatagram (datagram.data() , datagram.size() , &sender_adress); 
     server_ip = sender_adress; 

     QString message (datagram.data()); 

     cout << ">> NetworkManager: Broadcast message received: " << message.toStdString() << endl;  
     if (message == QString ("0:%1").arg (NetworkMessages::ConnectToServer)) 
     {   
     if (connection_status == 0) // If 0, there is no connection still. 
     { 
      cout << endl << " Server asking for connection." << endl; 
      cout << " Server IP: " << sender_adress.toString().toStdString() << endl; 
      cout << " Trying to connect." << endl; 
      server_connection->connectToHost (sender_adress , cfg->networkControl()->tcpPort());   
      cout << " Waiting for responce." << endl;   
      connection_status = 1; 
      break; 
     } 
     } 
    } 
    return; 
} 

, 나는 초기화 코드를 가지고 :

connection_server = new QTcpServer(); 
connect (connection_server , SIGNAL (newConnection()) , this , SLOT (connectClient())); 

if (connection_server->listen (QHostAddress::Any , cfg->networkControl()->tcpPort()) == false) 
{ 
    cout << ">> NetworkManager: Error setting port " << cfg->networkControl()->tcpPort() << " for TCP server use" << endl; 
} 

을 그리고 이것은 새로운 클라이언트 연결하는 코드의 일부입니다

void NetworkManager::connectClient (void) 
{ 
    cout << ">> NetworkManager: New client request." << endl; 
    QTcpSocket* new_client = connection_server->nextPendingConnection(); 
    connection_sockets[ i ] = new_client; // This is a QList of QTcpSocket pointers, the value of 'i' is calculated previously 
    connect (new_client , SIGNAL (readyRead()) , connection_listeners[ i ] , SLOT (readyRead())); 
    connect (new_client , SIGNAL (disconnected()) , connection_listeners[ i ] , SLOT (disconnected())); 
    connection_state[ i ] = 1; 

    cout << " Asking to client with IP " << new_client->peerAddress().toString().toStdString() << " identify." << endl; 
    connection_state[ i ] = 1; 

    sendToClient (QObject::tr ("0:%1").arg (NetworkMessages::IdentifyYourself) , i); 
} 

은 "sendToClient을" 멤버 함수는 일단 연결되면 클라이언트에게 메시지를 보냅니다.

그래서 문제는 내가 왜 그렇게 무작위로 연결되어 있는지 모릅니다. 대부분의 시간이 잘못된 연결입니다 (클라이언트는 다시 연결 신호를 내 보냅니다. 그러나 서버 쪽에서는 신호가 없습니다. 클라이언트가 연결할 때 방출 ...).

내가 잘못 뭘하는지 모르는

...

클라이언트와 서버 모두 이미 클라이언트, 서버 모두에 (TCP 포트 값을 변경 8888 UDP 포트 45454 및 TCP 포트와 함께 작동) 그리고 같은 이야기. TCP 포트를 변경했는데 둘 다 동일한 포트가 없으면 메시지가 클라이언트에 도달하지 않습니다 ...

죄송하지만 긴 텍스트는 유감스럽게 생각합니다. ...

내 문제가 될 수 있거나 내 코드에 문제가있는 경우 조언을 원하지만 때로는 (때로는 때때로) 한두 명의 클라이언트가 실제로 연결할 수 있습니다 ... void NetworkManager::broadcastMessageReceived(void)에서

답변

0

connection_status = 1;

는 없을 것이다. 연결이 성공하면 serverConnected()으로 설정해야합니다.

+0

connection_status 값은 연결 프로세스를 추적하기 위해 클라이언트에서 사용되는 정수 값입니다 (0 = 연결되지 않음, 1 = 서버 응답 대기 중, 2 = 암호 유효성 검사 대기 중, 3 = 연결됨). 내가 게시 할 때 코드에서 이러한 줄을 제거하는 것을 잊었습니다. 이 오류 수정으로 도움을받을 수 있기를 바랍니다. n_n –

관련 문제