Pregunta

Estamos escribiendo un proyecto donde hay un cliente que genera solicitudes XML, los envía a un servidor, que analiza la solicitud y devuelve la información solicitada en una cadena XML.

La aplicación funciona bien cuando las respuestas XML son pequeñas, pero cuando exceden alrededor de 2500 caracteres a veces conseguir cortado en el cliente final. A veces digo porque cuando el cliente y el servidor se ejecutan en la misma máquina y se comunican a través de la dirección 127.0.0.1 las respuestas se analizan muy bien. Sin embargo, cuando el cliente y el servidor están en máquinas diferentes y se comunican a través de LAN, esto es cuando el cliente corta el mensaje a alrededor de 2500 caracteres.

La comunicación se realiza mediante sockets TCP. Estamos utilizando Qt, el cliente tiene una qTCPsocket, y el servidor de un qTCPserver y un puntero a una qtcpsocket.

Creemos que una posible solución a nuestro problema está enviando el xml en pedazos, ya sea por separado o recuento de caracteres por etiqueta. Si bien es fácil para nosotros para romper el mensaje en partes, el envío de las partes y con el cliente o el servidor de lectura y compilar las partes en una sola solicitud XML está causando problemas para nosotros.

Por el bien de ejemplo, queríamos prueba que tiene el cliente envía una solicitud en varias partes.

Esta es nuestra llamada a la función de cliente para enviar una solicitud. xmlReq se genera en otro lugar y se hace pasar en. Como un ejemplo de romper el mensaje en partes nos despojamos de la etiqueta de cierre de la solicitud xml, y luego enviarlo como otra pieza más tarde.

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;

}

El siguiente es nuestro código de servidor. Está escrito en tal distancia que se supone que debe leer los mensajes desde el cliente hasta que se ve la etiqueta del mensaje de cierre XML, y luego procesar los datos y enviar la parte posterior respuesta al cliente.

Este es el código que inicia el servidor.

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

Cuando se hace una nueva conexión que llama la ranura AcceptConnection que se parece a esto

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

El startRead se ve así:

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

        }
    }}

En mi opinión, la lectura inicio se codifica de tal manera que en cualquier momento el cliente escribe un mensaje, el servidor lee y lo adjunta a la XMLRequest el servidor almacena. Si el mensaje contiene, la etiqueta de cierre XML, entonces se procesa la solicitud.

¿Qué ocurre, sin embargo, es si el cliente hace sucesivas escrituras, el servidor no ha leído todos ellos, sólo la primera, y nunca recibe la etiqueta de cierre xml, y por lo tanto no procesa las solicitudes.

La necesidad me pregunta por responder es ¿por qué no el servidor responda a los clientes múltiples escribe? ¿Cómo debo ir sobre lo que es tal que puedo enviar una cadena XML, desglosado en piezas, y tener el servidor de leer todas las piezas y convertirlo en una cadena de nuevo?

¿Fue útil?

Solución

Esto está sucediendo debido a la naturaleza "corriente" del protocolo TCP. Los datos se dividen en muchos paquetes, y en su aplicación, en realidad está leyendo sólo una parte de ellos (bytesAvailable () no es preciso que sea igual a la cantidad de bytes que el otro enviado de acogida, es sólo la cantidad de bytes están disponibles en el tampón socket). Lo que tiene que hacer es establecer un protocolo sencillo entre el cliente y el servidor. Por ejemplo, el cliente envía primero el carácter STX, a continuación, el XML, entonces el carácter ETX. Cuando el servidor ve un carácter STX, se lee todo en el buffer hasta que el carácter EXT. Otro enfoque - enviar un número entero de 4 bytes en orden de bytes de red que indica el tamaño de los datos XML en bytes, a continuación, enviar XML. El otro host debe recibir el número entero, convertirlo a su byteorder nativo, entonces leer la cantidad especificada de los datos de la toma de la memoria intermedia.

Otros consejos

En TCP, no es algo que se conoce como el tamaño máximo de segmento. Antes de la inicialización de la transferencia de datos, ambas partes deciden el SMS en la fase de apretón de manos SYN. Esa es la razón por la que sus datos están siendo separaron.

Sólo tiene una client.read (). El servidor enviará una respuesta para cada lectura procesado. Es necesario un mecanismo similar en el lado del cliente de mango lee. Una función que lee hasta que se ha leído un número N de bytes. Puede enviar el valor de N en el inicio de la transferencia de datos.

COMP 3004 veo. Tal pesadilla, hemos estado tratando con QXmlStreamReader y QXmlStreamWriter. El escritor es agradable y simple, pero el lector es una pesadilla, hemos estado tratando de utilizar el error PrematureEndOfDocument como punto de descanso para saber que hay más datos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top