以下是我目前使用的代码:
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();
}
答案 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);