2010-11-28 5 views
1

xml 요청을 생성하고 요청을 구문 분석하고 요청 된 정보를 xml 문자열로 반환하는 서버로 클라이언트를 보내는 클라이언트가있는 프로젝트를 작성합니다.Qt를 사용하여 TCP 소켓을 통해 xml 메시지를 보내려면

xml 응답이 작을 때 응용 프로그램이 제대로 작동하지만 약 2500자를 넘으면 클라이언트 끝에서 잘릴 수 있습니다. 클라이언트와 서버가 동일한 시스템에서 실행되고 집 주소 127.0.0.1을 통해 통신 할 때 응답이 잘 분석되기 때문에 때때로 말합니다. 그러나 클라이언트와 서버가 다른 시스템에 있고 LAN을 통해 통신하는 경우 클라이언트가 약 2500 자로 메시지를 자르는 경우입니다.

통신은 tcp 소켓으로 수행됩니다. 우리는 Qt를 사용하고 있고, 클라이언트는 qTCPsocket을 가지고 있고, 서버는 qTCPserver와 qtcpsocket을 가리키는 포인터를 가지고있다.

우리는 문제의 가능한 해결책이 xml을 문자 수나 태그로 구분하여 전송하는 것이라고 생각합니다. 메시지를 부분으로 나누기가 쉽지만 부분을 보내고 클라이언트 나 서버가 하나의 XML 요청으로 부품을 읽고 컴파일하면 문제가 발생합니다.

예를 들어 클라이언트가 여러 부분에서 요청을 보내도록 테스트하려고합니다.

다음은 요청을 보내기위한 클라이언트 함수 호출입니다. xmlReq는 어디에서 건 전달되었고 다른 곳으로 전달되었습니다. 메시지를 부분으로 나누는 예로서 xml 요청에서 닫는 태그를 제거한 다음 나중에 다른 부분으로 보냅니다.

QString ClientConnection::sendRequest(QString xmlReq) 
{ 

    this->xmlRequest = xmlReq; 

    QHostAddress addr(address); 

    QList<QString> messagePieces; 
    xmlRequest.remove("</message>"); 

    messagePieces.append(xmlRequest); 
    messagePieces.append("</message>"); 


    client.connectToHost(addr,6789); 

    if(client.waitForConnected(30000)) 
    { 
     for(int i = 0; i < messagePieces.length();i++) 
     { 
      client.write(messagePieces[i].toAscii(),messagePieces[i].length()+1); 
      qDebug() << "Wrote: " << messagePieces[i]; 
     } 
    } 


    char message[30000] = {0}; 

    xmlReply = ""; 

    if(client.waitForReadyRead(30000)){ 


     client.read(message,client.bytesAvailable()); 


    }else{ 
     xmlReply = "Server Timeout"; 
    } 

    client.close(); 
    xmlReply = (QString) message; 

    return xmlReply; 

} 

다음은 Google 서버 코드입니다. XML 닫는 메시지 태그를 볼 때까지 클라이언트에서 메시지를 읽은 다음 데이터를 처리하고 클라이언트에게 응답을 다시 보냅니다.

서버를 시작하는 코드입니다. 그것은이

void CETServer::acceptConnection() 
{ 
    client = server.nextPendingConnection(); 
    connect(client, SIGNAL(readyRead()), this, SLOT(startRead())); 
} 

처럼 보이는 acceptConnection 슬롯을 호출하는 새로운 연결을 얻을 때

//Start the server, pass it the handler so it can perform queries 
    connect(&server, SIGNAL(newConnection()), this, SLOT(acceptConnection())); 
    server.listen(QHostAddress::Any, 6789); 

은 startRead은 다음과 같습니다

내 마음에
void CETServer::startRead() 
{ 
    char buffer[1024*30] = {0}; 

    client->read(buffer, client->bytesAvailable()); 

    QString readIn; 

    readIn = (QString) buffer; 

    ui->statusText->appendPlainText("Received: " + readIn); 

    //New messages in will be opened with the xml version tag 
    //if we receive said tag we need to clear our query 
    if (readIn.contains("<?xml version =\"1.0\"?>",Qt::CaseSensitive)) 
    { 
     xmlQuery = ""; 
    } 

    //add the line received to the query string 
    xmlQuery += readIn; 

    //if we have the clsoe message tag in our query it is tiem to do stuf with the query 
    if(xmlQuery.contains("</message>")) 
    { 
     //do stuff with query 

     ui->statusText->appendPlainText("Query received:" + xmlQuery); 

     QString reply = this->sqLite->queryDatabase(xmlQuery); 
     xmlQuery = ""; 

     this->commandStatus(reply); 

     if(client->isWritable()){ 
      //write to client 
      client->write(reply.toAscii(),reply.length()+1); 
      ui->statusText->appendPlainText("Sent to client: " + reply); 
      client->close(); 

     } 
    }} 

이 시작 읽기입니다 클라이언트가 메시지를 쓸 때마다 서버는 메시지를 읽고 서버가 저장하는 xmlRequest에 연결합니다. 메시지에 xml 닫기 태그가 포함되어 있으면 요청을 처리합니다.

클라이언트가 연속 쓰기를 수행하고, 서버가 모두를 읽지 않으며, 첫 번째 메시지 만 읽고, xml 닫는 태그를받지 않으므로 요청이 처리되지 않습니다.

내가 대답해야하는 질문은 서버가 클라이언트가 여러 번 쓰는 것에 응답하지 않는 이유입니다. XML 문자열을 보내서 조각으로 나누어서 서버가 모든 조각을 읽고 다시 한 문자열로 바꿀 수 있도록 만드는 방법에 대해 어떻게해야합니까?

+0

이것은 보안 구멍입니다. "char 버퍼 [1024 * 30] = {0}; 클라이언트 -> 읽기 (버퍼, 클라이언트 -> bytesAvailable());" 버퍼에 피팅하는 것보다 더 많은 바이트가있을 수 있으며 버퍼 오버 플로우가 발생합니다. –

답변

0

TCP 프로토콜의 "스트림"특성 때문에 이러한 현상이 발생합니다. 데이터는 많은 패킷으로 분할되며 앱에서 실제로 일부만 읽습니다 (bytesAvailable()은 다른 호스트가 보낸 바이트 수와 같을 필요는 없습니다. 소켓 버퍼). 당신이해야 할 일은 클라이언트와 서버 사이에 간단한 프로토콜을 설정하는 것입니다. 예를 들어 클라이언트는 먼저 STX 문자를 보낸 다음 XML을 보낸 다음 ETX 문자를 보냅니다. 서버가 STX 문자를 볼 때 EXT 문자까지 버퍼에 모든 것을 읽습니다. 다른 접근법 - 바이트 단위의 XML 데이터 크기를 나타내는 네트워크 바이트 순서로 4 바이트 정수를 전송 한 다음 XML을 보냅니다. 다른 호스트는 정수를 받아서 기본 바이트 순서로 변환 한 다음 지정된 양의 데이터를 소켓에서 버퍼로 읽어야합니다.

1

TCP의 경우 최대 세그먼트 크기로 알려진 것이 있습니다. 데이터 전송을 초기화하기 전에 양 당사자가 SYN 핸드 셰이크 단계에서 MSS를 결정합니다. 이것이 귀하의 데이터가 분리되는 이유입니다.

하나의 client.read() 만 있습니다.서버는 처리 된 모든 읽기에 대한 응답을 보냅니다. 읽기를 처리하려면 클라이언트 측에서 비슷한 메커니즘이 필요합니다. N 바이트를 읽을 때까지 읽는 함수. 데이터 전송 시작시 값 N을 보낼 수 있습니다.

0

comp 3004 알 수 있습니다. 이러한 악몽, 우리는 QXmlStreamReader 및 QXmlStreamWriter를 사용해 왔습니다. 작가는 훌륭하고 간단하지만 독자는 악몽입니다. ​​우리는 더 많은 데이터가 있음을 알기위한 중단 점으로 PrematureEndOfDocument 오류를 사용하려고했습니다.