gpt4 book ai didi

c# - 没有消息帧的 TCP 上的 Xml

转载 作者:可可西里 更新时间:2023-11-01 02:54:22 25 4
gpt4 key购买 nike

我必须实现一个传输原始 xml 数据的 tcp 连接。不幸的是没有消息框架,我现在这真的很糟糕,但我必须处理这个......

消息看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<DATA></DATA>

或者这个

<?xml version="1.0" encoding="utf-8"?>
<DATA />

现在我必须接收可能带有自闭合标签的消息。消息总是一样的,它总是像 xml 描述和带有内部 xml 的数据标记,即消息内容。因此,如果没有自闭标签,这将很容易,但我如何才能同时阅读这两者?

顺便说一句,我正在使用 TcpListener。

编辑:如果没有自闭标签,一切都很好。

            if (_clientSocket != null)
{
NetworkStream networkStream = _clientSocket.GetStream();
_clientSocket.ReceiveTimeout = 100; // 1000 miliseconds

while (_continueProcess)
{
if (networkStream.DataAvailable)
{
bool isMessageComplete = false;
String messageString = String.Empty;
while (!isMessageComplete)
{
var bytes = new byte[_clientSocket.ReceiveBufferSize];
try
{
int bytesReaded = networkStream.Read(bytes, 0, (int) _clientSocket.ReceiveBufferSize);
if (bytesReaded > 0)
{
var data = Encoding.UTF8.GetString(bytes, 0, bytesReaded);
messageString += data;

if (messageString.IndexOf("<DATA", StringComparison.OrdinalIgnoreCase) > 0 &&
messageString.IndexOf("</DATA", StringComparison.OrdinalIgnoreCase) > 0)
{
isMessageComplete = true;
}

}
}
catch (IOException)
{
// Timeout
}
catch (SocketException)
{
Console.WriteLine("Conection is broken!");
break;
}
}

}

Thread.Sleep(200);
} // while ( _continueProcess )
networkStream.Close();
_clientSocket.Close();
}

编辑 2 (30.03.2015 12:00)

不幸的是,无法使用某种消息框架。所以我最终使用了这部分代码(DATA 是我的根节点):

            if (_clientSocket != null)
{
NetworkStream networkStream = _clientSocket.GetStream();
_clientSocket.ReceiveTimeout = 100;
string data = string.Empty;

while (_continueProcess)
{
try
{
if (networkStream.DataAvailable)
{

Stopwatch sw = new Stopwatch();
sw.Start();
var bytes = new byte[_clientSocket.ReceiveBufferSize];

int completeXmlLength = 0;
int bytesReaded = networkStream.Read(bytes, 0, (int) _clientSocket.ReceiveBufferSize);
if (bytesReaded > 0)
{
message.AddRange(bytes);
data += Encoding.UTF8.GetString(bytes, 0, bytesReaded);

if (data.IndexOf("<?", StringComparison.Ordinal) == 0)
{
if (data.IndexOf("<DATA", StringComparison.Ordinal) > 0)
{
Int32 rootStartPos = data.IndexOf("<DATA", StringComparison.Ordinal);
completeXmlLength += rootStartPos;
var root = data.Substring(rootStartPos);
int rootCloseTagPos = root.IndexOf(">", StringComparison.Ordinal);
Int32 rootSelfClosedTagPos = root.IndexOf("/>", StringComparison.Ordinal);
// If there is an empty tag that is self closed.
if (rootSelfClosedTagPos > 0)
{
string rootTag = root.Substring(0, rootSelfClosedTagPos +1);
// If there is no '>' between the self closed tag and the start of '<DATA'
// the root element is empty.
if (rootTag.IndexOf(">", StringComparison.Ordinal) <= 0)
{
completeXmlLength += rootSelfClosedTagPos;
string messageXmlString = data.Substring(0, completeXmlLength + 1);
data = data.Substring(messageXmlString.Length);
try
{
// parse complete xml.
XDocument xmlDocument = XDocument.Parse(messageXmlString);
}
catch(Exception)
{
// Invalid Xml.
}
continue;
}
}
if (rootCloseTagPos > 0)
{
Int32 rootEndTagStartPos = root.IndexOf("</DATA", StringComparison.Ordinal);
if (rootEndTagStartPos > 0)
{
var endTagString = root.Substring(rootEndTagStartPos);
completeXmlLength += rootEndTagStartPos;
Int32 completeEndPos = endTagString.IndexOf(">", StringComparison.Ordinal);
if (completeEndPos > 0)
{
completeXmlLength += completeEndPos;
string messageXmlString = data.Substring(0, completeXmlLength + 1);
data = data.Substring(messageXmlString.Length);
try
{
// parse complete xml.
XDocument xmlDocument = XDocument.Parse(messageXmlString);
}
catch(Exception)
{
// Invalid Xml.
}
}
}
}
}
}
}
sw.Stop();
string timeElapsed = sw.Elapsed.ToString();

}
}
catch (IOException)
{
data = String.Empty;
}
catch (SocketException)
{
Console.WriteLine("Conection is broken!");
break;
}
}

如果存在某种消息框架,我会使用这段代码,在本例中为 4 个字节的消息长度:

            if (_clientSocket != null)
{
NetworkStream networkStream = _clientSocket.GetStream();
_clientSocket.ReceiveTimeout = 100;
string data = string.Empty;

while (_continueProcess)
{
try
{
if (networkStream.DataAvailable)
{
Stopwatch sw = new Stopwatch();
sw.Start();

var lengthBytes = new byte[sizeof (Int32)];
int bytesReaded = networkStream.Read(lengthBytes, 0, sizeof (Int32) - offset);
if (bytesReaded > 0)
{
offset += bytesReaded;
message.AddRange(lengthBytes.Take(bytesReaded));
}
if (offset < sizeof (Int32))
{
continue;
}
Int32 length = BitConverter.ToInt32(message.Take(sizeof(Int32)).ToArray(), 0);

message.Clear();
while (length > 0)
{
Int32 bytesToRead = length < _clientSocket.ReceiveBufferSize ? length : _clientSocket.ReceiveBufferSize;
byte[] messageBytes = new byte[bytesToRead];
bytesReaded = networkStream.Read(messageBytes, 0, bytesToRead);
length = length - bytesReaded;
message.AddRange(messageBytes);
}

try
{
string xml = Encoding.UTF8.GetString(message.ToArray());
XDocument xDocument = XDocument.Parse(xml);
}
catch (Exception ex)
{
// Invalid Xml.
}
sw.Stop();
string timeElapsed = sw.Elapsed.ToString();
}
}
catch (IOException)
{
data = String.Empty;
}
catch (SocketException)
{
Console.WriteLine("Conection is broken!");
break;
}
}

如您所见,我想测量耗时,以查看 witch methode 是否具有更好的性能。奇怪的是,没有消息帧的方法的平均时间为 0,2290 毫秒,另一个方法的平均时间为 1,2253 毫秒。有人可以向我解释为什么吗?我以为没有消息框架的会更慢......

最佳答案

NetworkStream 交给 .NET XML 基础结构。例如,从 NetworkStream 创建一个 XmlReader

不幸的是,我没有找到一种内置的方法来轻松地从一个包含多个文档的 XmlReader 创建一个 XmlDocument。它提示多个根元素(这是正确的)。您需要包装 XmlReader 并使其在第一个文档完成后停止返回节点。您可以通过跟踪某些状态并查看嵌套级别来做到这一点。当嵌套级别再次为零时,第一个文档就完成了。

这只是一个草图。我很确定这会起作用,并且它可以处理所有 可能的 XML 文档。

不需要您那里的这种可怕的字符串处理代码。现有代码看起来也很慢,但由于这种方法要好得多,因此对性能问题发表评论没有任何意义。你需要把它扔掉。

关于c# - 没有消息帧的 TCP 上的 Xml,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29300939/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com