Async Receive, множественный прием XML-данных, иногда вызывающий ошибку нескольких корневых элементов - PullRequest
1 голос
/ 22 января 2012

Вот код, который я сейчас использую:

if (bytesRead > 0)
{                    
    if (recievedData.Trim().EndsWith("</CRootSystem>", stringComparison.Ordinal))
    {
        if (state.packetCount > 0)
        {
            state.sb.Append(recievedData);
            state.totalSize += bytesRead;
            state.packetCount++;

            totalSize = state.totalSize;

            #region Insert into Packet
                Packet packet = new Packet(state.totalSize, state.packetCount);
                packetManager.Packets.Add(packet);
            #endregion

            parseXmlFeed(state.sb.ToString());

            #region Reset
                state.clear();
                recievedData = null;
            #endregion
        }
        else            
        {
            totalSize = bytesRead;

            #region Insert into Packet
                Packet packet = new Packet(state.totalSize, state.packetCount);
                packetManager.Packets.Add(packet);
            #endregion

            parseXmlFeed(recievedData);
        }
    }
    else
    {
        state.sb.Append(recievedData);
        state.totalSize += bytesRead;
        state.packetCount++;
    }
}
else //This part of code will never reached, because the connection and comm. with the server is never closed
{
    Display.Write("Nomore data Recieved.");
    receiveDone.Set();
}

Этот код на самом деле прекрасно работает.Но иногда я получаю сообщение об ошибке при синтаксическом анализе XML parseXmlFeed (s);

Я получаю следующую ошибку:

Существует несколько корневых элементов.Строка X, позиция Y.

Я знаю, что означает эта ошибка.У меня есть более одного корневого элемента в моих xml-данных.

Но сервер никогда не отправляет неправильный xml.Сервер отправляет длинные данные (каждый по 8192 байт)

Пример: [8192 байт] + [8192 байт] + [176 байт]

Но теоретически у меня никогда не должно быть xml-данных с2 корня.

Я действительно застрял в этой точке.

Я думаю, что у меня есть ошибка, когда я добавляю данные или должен использовать блокировку, мьютекс, полуфор или монитор?

Должен ли я заблокировать данные перед добавлением?

или вопрос в том, как правильно обрабатывать длинные данные?

Кстати.Я использую BeginReceive / EndReceive.

Изменил вышеуказанный код на:

    if (bytesRead > 0)
    {
        state.sb.Append(recievedData);
        state.totalSize += bytesRead;
        state.packetCount++;

        string data = state.sb.ToString();
        int dataSize = state.totalSize;

        if (data.TrimEnd().EndsWith("</CRootSystem>", StringComparison.Ordinal))
        {
            #region Insert into Packet
                Packet packet = new Packet(state.totalSize, state.packetCount);
                packetManager.Packets.Add(packet);
            #endregion

            parseXmlFeed(data);

            #region Reset
                state.clear();
                recievedData = null;
            #endregion
        }
        else
        {
            Display.Write("Waiting...");
        }
    }
    else 
    {
        Display.Write("No more data Recieved.");
        receiveDone.Set();
    }

1 Ответ

1 голос
/ 22 января 2012

Исходя из вашего объяснения, я предполагаю, что вы получаете сообщение об ошибке при получении нескольких элементов <CRootSystem> за одно чтение.Размер буфера 8192 байта задается не сервером, а свойством ReceiveBufferSize вашего TcpClient (значение по умолчанию которого равно 8192 байта).Таким образом, если сервер отправляет несколько пакетов данных в последовательной последовательности, вы можете получить их в рамках одного BeginReceive обратного вызова.

Другая проблема: что, если общий размер одного <CRootSystem> документа окажетсяскажем, 8195 байт?В этом случае первое чтение даст вам <CRootSystem>…(data)…</CRootSyst, а второе чтение даст вам em>.Условие EndsWith("</CRootSystem>") никогда не выполняется, поскольку тег закрытия никогда полностью не содержится в recievedData.

Ваш код потребует существенной доработки.Для начала, для правильности (но не эффективности), вы можете заменить:

if (recievedData.Trim().EndsWith("</CRootSystem>", stringComparison.Ordinal))

на:

state.sb.Append(receivedData);
int endTagIndex = state.sb.ToString().IndexOf("</CRootSystem>", StringComparison.Ordinal);
if (endTagIndex != -1)

… и затем извлечь ваш XML из первых endTagIndex + "</CRootSystem>".Length символовВаша строка.

Редактировать : Вот быстрое и грязное исправление, чтобы остановить вашу ошибку.Заменить:

parseXmlFeed(data);

на:

Regex rootRegex = new Regex(@"<CRootSystem.*?</CRootSystem>", RegexOptions.Singleline);
foreach (Match match in rootRegex.Matches(data))
    parseXmlFeed(match.Value);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...