草庐IT

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

coder 2023-09-20 原文

我必须实现一个传输原始 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/

有关c# - 没有消息帧的 TCP 上的 Xml的更多相关文章

  1. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

    我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

  2. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  3. ruby-on-rails - rails 目前在重启后没有安装 - 2

    我有一个奇怪的问题:我在rvm上安装了ruby​​onrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(

  4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  5. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

    我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

  6. ruby-on-rails - openshift 上的 rails 控制台 - 2

    我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

  7. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  8. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  9. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  10. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

随机推荐