Frage

Wir sind ein Projekt zu schreiben, wo es ist ein Kunde, XML-Anfragen generiert, sendet sie an einen Server, der die Anforderung und gibt die angeforderten Informationen in einer XML-Zeichenfolge analysiert.

Die Anwendung funktioniert gut, wenn die XML-Antworten klein sind, aber wenn sie etwa 2500 Zeichen nicht überschreiten sie manchmal auf der Client-Seite abgeschnitten werden. Ich sage manchmal, weil, wenn der Client und Server auf der gleichen Maschine laufen und kommunizieren über die Home-Adresse 127.0.0.1 die Antworten nur gut analysiert werden. Wenn jedoch der Client und Server auf verschiedenen Maschinen sind und kommunizieren über lan, das ist, wenn der Client die Nachricht auf rund 2500 Zeichen schneidet.

Die Kommunikation erfolgt über TCP-Sockets erfolgen. Wir verwenden Qt, der Kunde hat einen QTcpSocket, und der Server ein qTCPserver und einen Zeiger auf eine QTcpSocket.

Wir denken, dass eine mögliche Lösung für unser Problem ist die XML in Stücken zu senden, entweder getrennt durch Zeichenzahl oder nach Tag. Während es einfach ist für uns die Nachricht in Teile zu brechen, um die Teile zu senden und den Client oder Server liest und die Teile in eine XML-Anforderung zusammenstellen verursacht uns Schwierigkeiten.

Aus Gründen des Beispiels wir testen wollten, die der Client eine Anforderung in mehreren Teilen senden.

Hier ist unser Client-Funktionsaufruf eine Anfrage zu senden. xmlReq erzeugt sonst wo und übergeben. Als Beispiel für die Nachricht in Teile brechen wir den Schluss-Tag aus der XML-Anfrage abstreifen und dann später als ein weiteres Stück senden.

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;

}

Als nächstes ist unser Server-Code. Es ist in einem solchen weg geschrieben, dass es angeblich Nachrichten vom Client zu lesen, bis es die XML-Abschlussmeldung Tag sieht und dann die Daten verarbeiten und die Antwort zurück an den Client senden.

Dies ist der Code, der den Server gestartet wird.

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

Wenn es wird eine neue Verbindung des acceptConnection Slot ruft die wie diese

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

Die Starte sieht wie folgt aus:

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

        }
    }}

In meinem Kopf, der Anfang Lese derart codiert, dass jederzeit der Client eine Nachricht schreibt, liest der Server sie und ordnet es den XMLRequest speichert der Server. Wenn die Nachricht enthält, Tag der XML-Schließung, dann verarbeitet es die Anfrage.

Was allerdings passiert, ist, wenn der Kunde aufeinanderfolgende Schreibvorgänge der Fall ist, der Server sie nicht alles lesen, nur die erste und erhält nie die XML-End-Tag und verarbeitet daher keine Anfragen.

Die Notwendigkeit Frage, die ich beantwortet ist, warum nicht der Server reagiert auf die Clients mehrere schreiben? Wie soll ich gehen darum, es so, dass ich eine XML-Zeichenfolge senden können, in Stücke zerbrochen und haben der Server alle Stücke lesen und in einen String wieder einschalten?

War es hilfreich?

Lösung

Das geschieht, weil die „Strom“ Natur des TCP-Protokolls. Die Daten sind aufgeteilt in viele Pakete, und in Ihrer Anwendung, gerade lesen Sie wirklich nur einen Teil von ihnen (bytesAvailable () ist nicht erforderlich, die gleich der Anzahl der Bytes der anderen Host gesendet, es ist nur, wie viele Bytes sind in der Socket-Puffer). Was Sie tun müssen, ist ein einfaches Protokoll zwischen dem Client und dem Server herzustellen. Zum Beispiel sendet der Client zuerst das STX-Zeichen, dann der XML, dann ETX-Zeichen. Wenn der Server ein STX-Zeichen sieht, liest er alles in die bis zum EXT Zeichen puffern. Anderer Ansatz - sendet 4-Byte-Integer in Netzwerk-Byte-Reihenfolge die Größe von XML-Daten in Bytes angibt, dann XML senden. Der andere Host die ganze Zahl erhalten muß, wandelt es in seinem nativen byteorder, dann lesen Sie die angegebene Menge an Daten aus der Steckdose in den Puffer.

Andere Tipps

In TCP, gibt es etwas wie das Maximum Segment Size bekannt. Vor der Initialisierung der Datenübertragung, entscheiden beide Parteien die MSS in der Handshake-Phase SYN. Das ist der Grund, warum Ihre Daten Split werden nach oben.

Sie haben nur einen client.read (). Der Server wird eine Antwort für jede Lese verarbeitet senden. Sie benötigen einen ähnlichen Mechanismus auf der Client-Seite Griff liest. Eine Funktion, die bis es liest hat N Anzahl der gelesenen Bytes. Sie können den Wert N zu Beginn Ihrer Datenübertragung senden.

COMP 3004 ich sehe. Ein solcher Alptraum, haben wir mit QXmlStreamReader und QXmlStreamWriter versucht. Der Autor ist schön und einfach, aber der Leser ein Alptraum ist, wir haben versucht worden, um die PrematureEndOfDocument Fehler als Bruchstelle zu verwenden, um zu wissen, gibt es mehr Daten vorhanden sind.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top