代码之家  ›  专栏  ›  技术社区  ›  Belekz

字节数组封装数据包

  •  1
  • Belekz  · 技术社区  · 7 年前

    我正在为需要使用CIP协议通过TCP/IP进行通信的应用程序构建一个C#库。(这是PLC使用的工业协议)。我的库基于开源VB。net项目。

    enter image description here

    我在Microsoft开发人员网络上找到了很多信息来设置套接字。下一步是注册会话,因此我需要使用 插座接收方法 . 同样,关于开发人员网络的许多有用信息。

    我正在构建标题,如下所示:

    private string Build_Header(byte[] Command, int Length) //Build the encapsulate message header. The header is 24 bytes fixed length and includes the command and the length of the optional data portion
        {
            string Header;
            byte[] HeaderStatus = { 0x0, 0x0, 0x0, 0x0 };
            byte[] HeaderOption = { 0x0, 0x0, 0x0, 0x0 };
    
            try
            {
                Header = Encoding.Unicode.GetString(Command);
                Header += Encoding.Unicode.GetString(BitConverter.GetBytes(Length));
                Header += Encoding.Unicode.GetString(BitConverter.GetBytes(SessionID));
                Header += Encoding.Unicode.GetString(HeaderStatus);
                Header += Encoding.Unicode.GetString(BitConverter.GetBytes(Context));
                Header += Encoding.Unicode.GetString(HeaderOption);
    
                return Header;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Failed to create header: {0}", ex);
                return "FAILED";
            }
        }
    

    Witch是VB函数的副本:

    Private Function _build_header(Command As Byte(), length As Short)
        'Build the encapsulate message header
        'The header is 24 bytes fixed length, and includes the command and the length of the optional data portion.
        Dim header As String
        Try
            header = Encoding.Unicode.GetString(Command)                             '# Command UINT
            header += Encoding.Unicode.GetString(BitConverter.GetBytes(length))      '# Length UINT
            header += Encoding.Unicode.GetString(BitConverter.GetBytes(_session))    '# Session Handle UDINT
            header += Encoding.Unicode.GetString({&H0, &H0, &H0, &H0})               '# Status UDINT
            header += Encoding.Unicode.GetString(BitConverter.GetBytes(_Context))    '# Sender Context 8 bytes
            header += Encoding.Unicode.GetString({&H0, &H0, &H0, &H0})               '# Option UDINT
            'If Not DisableLogFile Then Console.WriteLine("Header created: " + Bytes_To_String(Encoding.Unicode.GetBytes(header)) + "  , length: " _
            '                    + header.Length.ToString + "   (must be equal to 24 bytes)")
            Return header
        Catch ex As Exception
            Console.WriteLine("Failed to create header: " + ex.Message)
            Return ""
        End Try
    End Function
    

    但我收到一条错误消息,状态为“不支持的封装协议修订版”因此,我开始一行接一行地调试,并发现以下差异:

    原件(VB):

    VB

    复制(C#):

    enter image description here

    我不确定这是否是主要问题,但我想至少应该是相同的格式?

    1 回复  |  直到 7 年前
        1
  •  3
  •   Marc Gravell    7 年前

    Oof;从何处开始。K: 坦率地说,你正在复制的VB参考资料 是垃圾 . 这是百分之百的错误,任何现在起作用的事情都完全是偶然的。首先,这些数据 不是文本 -这是一个二进制帧。因此,您 不能 回来 string . 返回 byte[] 这是合理的。因此,最重要的问题可能不是“如何获取此字符串”,而是“一旦拥有此字符串,如何将其写入套接字”?你的问题中没有显示该代码,但我很乐意打赌 如何将字符串写入套接字 是两个版本之间的关键区别。

    但是:你 首先不应该处理字符串 . 假设该方法返回 字节[] . 然后我们有:

    byte[] header = BuildHeader(command, length);
    

    现在我们只有一种方法 字节[] 到溪流(除非我们非常想象):

    socket.Send(header, 0, header.Length);
    

    (或涉及 Stream )

    现在什么 BuildHeader 应该 正在做的事情类似于:

    byte[] header = new byte[24];
    // .. fill in
    return header;
    

    至于这些部分应该是什么:这取决于 端度 ; 看起来像 UINT 为2字节,且 UDINT 是4。举个写作的例子 length (第二个字段,2字节,偏移量2字节),即 任何一个 :

    header[2] = (byte)length;
    header[3] = (byte)(length >> 8);
    

    header[2] = (byte)(length >> 8);
    header[3] = (byte)length;
    

    不幸地 BitConverter.GetBytes 不能帮助您打包缓冲区,因为a:它不允许您传入缓冲区和偏移量,b:定义了endianness 通过您的CPU (我们需要它是一个特定的endianness)。如果VB代码正常工作,它可能是little endian(除非您有安腾),因此第一个版本(little end first)应该是正确的。

    对所有字段重复该操作,就会得到一个有效的标题。