异步接收,多个Xml数据接收,有时会导致多个根元素错误

时间:2012-01-22 15:56:01

标签: c# xml-parsing

以下是我目前使用的代码:

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-data中有多个Root元素。

但是服务器从不发送错误的xml。服务器发送长数据(每个8192byte)

示例:[8192字节] + [8192字节] + [176字节]

但理论上,我永远不应该有一个带有2个根的xml数据。

我真的陷入了困境。

我认为在附加数据或使用锁定,互斥锁,半导体或监视器时出错?

我应该在追加之前锁定数据吗?

或问题是,如何正确处理长数据?

顺便说一下。我正在使用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 个答案:

答案 0 :(得分:1)

根据您的解释,我猜您在单次读取中收到多个<CRootSystem>元素时会收到错误。 8192字节的缓冲区大小不是由服务器设置的,而是由TcpClient的{​​{3}}属性设置的(其默认值恰好是8192字节)。因此,如果服务器连续发送多批数据,您可能会在一个BeginReceive回调中收到它们。

另一个问题:如果单个<CRootSystem>文档的总大小恰好是8195字节会怎么样?在这种情况下,第一次阅读会给你<CRootSystem>…(data)…</CRootSyst,而第二次阅读会给你em>。永远不会满足EndsWith("</CRootSystem>")条件,因为close标记永远不会完全包含在recievedData中。

您的代码需要进行一些重要的修改。首先,为了正确(但不是效率),您可以替换:

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

使用:

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

...然后从字符串的第一个endTagIndex + "</CRootSystem>".Length字符中提取XML。

编辑:这是一个快速而又脏的修复程序,可以阻止您的错误。替换:

parseXmlFeed(data);

使用:

Regex rootRegex = new Regex(@"<CRootSystem.*?</CRootSystem>", RegexOptions.Singleline);
foreach (Match match in rootRegex.Matches(data))
    parseXmlFeed(match.Value);
相关问题