字节数组中的封装包

时间:2018-01-29 12:47:48

标签: c# arrays sockets tcp

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

enter image description here

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

我正在构建这样的标题:

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

但是我收到一条错误消息,状态为“Unsupported encapsulation protocol revision”。所以我开始一行一行地调试,发现了以下不同之处:

原创(VB):

VB

复制(C#):

enter image description here

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

1 个答案:

答案 0 :(得分:3)

OOF;从哪儿开始。 K:我会坦率地说 - 你从复制的VB参考资料是垃圾。这是100%的错误,任何现在正在运作的东西都完全是偶然的。对于初学者来说,这个数据不是文本 - 它是一个二进制框架。因此,您无法返回string。返回byte[]是合理的。因此,最重要的问题可能不是&#34;我应该如何得到这个字符串&#34;,而是&#34;一旦我有了这个字符串,我怎么把它写到套接字&#34;?该代码未在您的问题中显示,但我很高兴地打赌,如何将字符串写入套接字是两个版本之间的关键区别。< / p>

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

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

现在只有一种方法可以将byte[]写入流中(除非我们非常想象):

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

(或涉及Stream

的某些类似变体

现在; BuildHeader 应该做的事情是这样的:

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

至于那些部分应该是什么:它取决于 endianness ;看起来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并没有帮助你打包缓冲区,因为它:它不允许你传递缓冲区和偏移量,而b:字节序定义由你的CPU (我们需要它是一个特定的字节顺序)。如果VB代码有效,它可能是little-endian(除非你有一个Itanium),所以第一个版本(first end first)应该是正确的。

对所有字段重复此操作,您将拥有有效的标题。

相关问题