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

本文关键字:错误 元素 Xml 多个 数据 异步 | 更新日期: 2023-09-27 18:20:58

这是我目前使用的代码:

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

这个代码实际上工作得很好。但有时我会在解析XMLparseXmlFeed时出错

我得到以下错误:

有多个根元素。行X,位置Y

我知道这个错误意味着什么。我的xml数据中有不止一个根元素。

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

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

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

我真的陷入了困境。

我想我在附加数据的地方有错误,或者应该使用锁、互斥、符号或监视器?

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

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

Btw。我正在使用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();
    }

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

根据您的解释,我猜测当您在一次读取中接收到多个<CRootSystem>元素时会出现错误。8192字节的缓冲区大小不是由服务器设置的,而是由TcpClientReceiveBufferSize属性设置的(其默认值恰好是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)

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

编辑:这里有一个快速而肮脏的修复程序来阻止您的错误。替换:

parseXmlFeed(data);

带有:

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