【问题标题】:How to deal with network data packets in a client/server application code?如何处理客户端/服务器应用程序代码中的网络数据包?
【发布时间】:2020-10-15 06:42:33
【问题描述】:

我正在使用 C# 创建一个客户端/服务器应用程序,我想知道在 C# 代码中处理数据包的最佳方法。

根据我的阅读,我可以 A)使用 Marshal 类从数据包原始缓冲区构造一个安全类,或者 B)在不安全的上下文中使用原始指针将数据包缓冲区直接转换为结构并使用它我的代码。

我可以看到这两种方法都有很大的问题。例如,使用 Marshal 似乎非常麻烦且难以维护(与指针解决方案相比),另一方面,在 C# 中指针的使用非常有限(例如,我什至不能声明非原始类型的固定大小数组这是此类应用程序中的交易破坏者)。

也就是说,我想知道这两种方法中哪一种更适合处理网络数据包,以及是否有其他更好的方法。我愿意接受任何其他可能的解决方案。

PS.:我实际上是在为已经存在的客户端/服务器应用程序创建一个自定义客户端,因此客户端和服务器之间的通信协议已经创建并且无法修改。所以我的 C# 客户端需要遵守这个已经存在的协议到其较低级别的细节(例如,数据包中每个信息的二进制偏移量是固定的,需要得到尊重)。

【问题讨论】:

  • 坦率地说,您不应该通过编组器解码套接字数据。您应该编写一个协议处理程序,该处理程序相当手动地查看字节流,获取协议需要的内容。协议很少符合编组要求,甚至在讨论字节序、编码等之前。顺便说一句,c# 完全支持非基元的固定大小的缓冲区——它们被称为“固定缓冲区”
  • 我有一个由 4 部分组成的博客系列,讨论了可能有用的现代方法,开始于:blog.marcgravell.com/2018/07/pipe-dreams-part-1.html
  • 您正在处理网络的 7 层中的两个。 1) 通过流(TCP 或 UDP)串行发送数据的传输层。这就是 Marc link 所描述的。 2) 应用层,您有一个要发送/接收的类对象。所以你真的在问将类转换为字节和字节转换为类的应用层。 c# 是一个托管库,不容易允许字节与类之间的转换。
  • Microsoft 设计了 ​​c# 托管库来消除 Win XP 之前(win 95、win 98、win 2000、win ME、WinNt)Windows 中经常出现的蓝屏崩溃。当指针未正确配置时,通常会出现蓝屏错误。因此,当 Net 3.5(与 Win XP 相同)几乎不可能使用指针并在托管库中添加了大量检查以防止蓝屏异常。 Marshal 库有防止蓝屏的检查,而不安全模式没有检查。
  • c# 不是将对象转换为字节的最有效语言(需要发送/接收)。您可以使用二进制序列化进行强制转换。如果您需要更高效的代码,请使用 c++。

标签: c# client-server marshalling


【解决方案1】:

处理网络数据包的最佳方法。您必须创建附加到实际数据包标头的有效负载,并且接收客户端始终首先读取标头并将其转换为实际长度。然后设置您在标头中收到的缓冲区长度。它将完美地工作而不会丢失任何数据包。它还将改善内存泄漏问题。您无需创建硬编码数组即可获取缓冲区字节。只需将实际字节长度附加到数据包的标头即可。它将动态设置缓冲区字节。

喜欢。

  public void SendPackettoNetwork(AgentTransportBO ObjCommscollection, Socket Socket)
    {
        try
        {
            byte[] ActualBufferMessage = PeersSerialization(ObjCommscollection);
            byte[] ActualBufferMessagepayload = BitConverter.GetBytes(ActualBufferMessage.Length);
            byte[] actualbuffer = new byte[ActualBufferMessage.Length + 4];
            Buffer.BlockCopy(ActualBufferMessagepayload, 0, actualbuffer, 0, ActualBufferMessagepayload.Length);
            Buffer.BlockCopy(ActualBufferMessage, 0, actualbuffer, ActualBufferMessagepayload.Length, ActualBufferMessage.Length);
            Logger.WriteLog("Byte to Send :" + actualbuffer.Length, LogLevel.GENERALLOG);
            Socket.Send(actualbuffer);
        }
        catch (Exception ex)
        {
            Logger.WriteException(ex);
        }
    }

只需传递您的传输类对象。在这里使用你的序列化方法我使用了类对象的二进制格式化程序序列化

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-05
    • 1970-01-01
    • 1970-01-01
    • 2011-02-06
    • 1970-01-01
    相关资源
    最近更新 更多