Domanda

Stiamo scrivendo un progetto in cui v'è un cliente che genera richieste XML, li invia a un server, che analizza la richiesta e restituisce le informazioni richieste in una stringa XML.

L'applicazione funziona bene quando le risposte XML sono piccole, ma quando superano circa 2500 caratteri a volte ottenere tagliato sul lato client. Dico a volte perché quando il client e il server eseguiti sulla stessa macchina e comunicano attraverso l'indirizzo di casa 127.0.0.1 le risposte vengono analizzate bene. Tuttavia, quando il client e il server sono su macchine diverse e comunicare su rete LAN, questo è quando il cliente taglia il messaggio a circa 2500 caratteri.

La comunicazione è fatto da socket TCP. Stiamo usando Qt, il cliente ha un qTCPsocket, e il server un qTCPserver e un puntatore a un qtcpsocket.

Pensiamo che una possibile soluzione al nostro problema sta inviando il codice XML in pezzi, sia separato dal conte carattere o per tag. Mentre è facile per noi a rompere il messaggio in parti, inviando le parti e con il client o server leggere e compilare le parti in una sola richiesta xml sta causando noi problemi.

Per motivi di esempio, abbiamo voluto testare avere il client invia una richiesta in più parti.

Ecco la nostra chiamata di funzione client per inviare una richiesta. xmlReq viene generato altrove e passata. Come esempio di rompere il messaggio in parti eliminiamo il tag di chiusura dalla richiesta XML, e inviarlo come un altro pezzo tardi.

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;

}

Il prossimo è il nostro codice del server. E 'scritto in tale via che si suppone di leggere i messaggi dal client fino a quando non vede il tag di chiusura messaggio XML e quindi elaborare i dati e inviare la risposta indietro al client.

Questo è il codice che avvia il server.

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

Quando si riceve una nuova connessione che chiama lo slot acceptConnection che assomiglia a questo

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

Lo startRead assomiglia a questo:

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();

        }
    }}

Nella mia mente, la lettura di inizio viene codificato in modo tale che ogni volta che un cliente scrive un messaggio, il server lo legge e lo collega al XMLRequest il server memorizza. Se il messaggio contiene, il tag di chiusura xml, allora elabora la richiesta.

Cosa succede, però, è se il cliente fa successive operazioni di scrittura, il server non li legge, solo il primo, e non riceve mai il tag di chiusura xml, ed elabora quindi, nessuna richiesta.

La necessità che domanda ha risposto è il motivo per cui non fa il server di rispondere ai clienti multipli scrive? Come devo fare per fare in modo che si posso inviare una stringa XML, suddiviso in pezzi, e che il server leggere tutti i pezzi e di trasformarlo in una stringa di nuovo?

È stato utile?

Soluzione

che sta accadendo a causa della natura "stream" del protocollo TCP. Il dato è divisa in molti pacchetti, e nella vostra app, sei davvero leggere solo una parte di essi (bytesAvailable () non è necessario uguale alla quantità di byte all'altro SENT padrone di casa, è solo quanti byte sono disponibili nel tampone socket). Quello che devi fare è quello di stabilire un semplice protocollo tra il client e il server. Ad esempio, il client prima invia il carattere STX, quindi il codice XML, quindi carattere ETX. Quando il server vede un carattere STX, si legge tutto nel buffer fino a quando il carattere EXT. Altro approccio - inviare un intero di 4 byte per byte di rete indica la dimensione dei dati XML in byte, quindi inviare XML. L'altro host deve ricevere l'intero, convertirlo sua byteorder nativo, quindi leggere la quantità specificata di dati dalla rete per il buffer.

Altri suggerimenti

In TCP, c'è qualcosa di conosciuto come il Maximum Segment Size. Prima di inizializzazione del trasferimento dei dati, entrambe le parti decidono MSS nella fase di handshake SYN. Questo è il motivo per cui i dati sono essere divisa.

Hai solo una client.read (). Il server invierà una risposta per ogni lettura elaborati. Avete bisogno di un meccanismo simile sul lato client per manico legge. Una funzione che legge fino a che non ha letto il numero N di byte. È possibile inviare il valore N all'inizio del tuo trasferimento dei dati.

COMP 3004 che vedo. Un tale incubo, abbiamo cercato con QXmlStreamReader e QXmlStreamWriter. Lo scrittore è bello e semplice, ma il lettore è un incubo, abbiamo cercato di utilizzare l'errore PrematureEndOfDocument come un punto di rottura per la sapendo che la struttura più dati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top