Отправка xml-сообщения по частям через TCP-сокет с использованием Qt - PullRequest
1 голос
/ 28 ноября 2010

Мы пишем проект, в котором есть клиент, который генерирует XML-запросы, отправляет их на сервер, который анализирует запрос и возвращает запрошенную информацию в XML-строке.

Приложение работает нормально, когдаxml-ответы небольшие, но когда они превышают около 2500 символов, они иногда обрезаются на стороне клиента.Я иногда говорю, потому что, когда клиент и сервер работают на одной машине и общаются через домашний адрес 127.0.0.1, ответы анализируются очень хорошо.Однако, когда клиент и сервер находятся на разных компьютерах и обмениваются данными по локальной сети, это происходит, когда клиент обрезает сообщение до примерно 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;

}

Далее идет нашкод сервера.Он написан так, что он должен читать сообщения от клиента до тех пор, пока он не увидит тег сообщения закрытия XML, а затем обработать данные и отправить ответ обратно клиенту.

Это код, которыйзапускает сервер.

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

Когда он получает новое соединение, он вызывает слот acceptConnection, который выглядит так1024 * На мой взгляд, начальное чтение кодируется таким образом, что каждый раз, когда клиент пишет сообщение, сервер читает его и присоединяет его к xmlRequest, который хранит сервер.Если сообщение содержит закрывающий тег xml, то он обрабатывает запрос.

Что происходит, если клиент выполняет последовательные записи, сервер не читает их все, только первое, и никогда не получаетзакрывающий тег xml, поэтому он не обрабатывает запросы.

Мне нужно ответить на вопрос, почему сервер не отвечает на запросы клиентов на множественные записи?Как мне сделать так, чтобы я мог отправить строку XML, разбитую на части, и чтобы сервер прочитал все части и снова превратил их в одну строку?

Ответы [ 3 ]

1 голос
/ 28 ноября 2010

В TCP существует так называемый максимальный размер сегмента.Перед инициализацией передачи данных обе стороны выбирают MSS на этапе установления связи SYN.Это причина, почему ваши данные разделяются.

У вас есть только один client.read ().Сервер отправит ответ на каждое обработанное чтение.Вам необходим аналогичный механизм на стороне клиента для обработки операций чтения.Функция, которая читает до тех пор, пока не прочитает N байтов.Вы можете отправить значение N в начале вашей передачи данных.

0 голосов
/ 01 декабря 2010

COMP 3004 Понятно.Такой кошмар мы пробовали с QXmlStreamReader и QXmlStreamWriter.Писатель хороший и простой, но читатель - это кошмар, мы пытались использовать ошибку PrematureEndOfDocument в качестве точки останова, зная, что данных больше.

0 голосов
/ 28 ноября 2010

Это происходит из-за «потоковой» природы протокола TCP. Данные разбиты на множество пакетов, и в вашем приложении вы действительно читаете только часть из них (bytesAvailable () необязательно равно количеству байтов, отправленных другим хостом, просто количество байтов доступно в буфер буфера). Что вам нужно сделать, это установить простой протокол между клиентом и сервером. Например, клиент сначала отправляет символ STX, затем XML, а затем символ ETX. Когда сервер видит символ STX, он считывает все в буфер вплоть до символа EXT. Другой подход - отправить 4-байтовое целое число в сетевом порядке байтов, указывающее размер данных XML в байтах, затем отправить XML. Другой хост должен получить целое число, преобразовать его в свой собственный метеородер, а затем прочитать указанный объем данных из сокета в буфер.

...