C#移植VB.NET CIP协议库时遇封装协议版本不支持错误
Let's break down why you're hitting this error and fix it step by step. The root issue is that your C# header implementation diverges from the original VB.NET code in critical ways that violate the CIP encapsulation protocol's 24-byte fixed header structure and byte ordering rules.
Key Issues in Your Current C# Code
- Length parameter mismatch: The original VB code uses a
Short(2 bytes) for the length field, but your C# code uses anint(4 bytes). This immediately adds 2 extra bytes to your header, breaking the required 24-byte total length. - Incorrect byte-to-string handling: Using
Encoding.Unicode.GetString()to convert byte arrays to strings and then concatenating them is a mistake. Strings are designed for text, not raw binary data—this can introduce unexpected encoding artifacts and corrupt your header bytes when you eventually convert the string back to bytes for sending. - Missing endianness handling: CIP encapsulation protocol uses big-endian (network byte order) for multi-byte fields, but
BitConverter.GetBytes()returns little-endian bytes on x86/x64 systems. Your VB code might have implicitly handled this (or the original project had helper methods you missed), but your C# code doesn't account for it. - Context field size: The CIP header's Sender Context field is 8 bytes, but your code uses
BitConverter.GetBytes(Context)which outputs 4 bytes ifContextis anint—another violation of the fixed header structure.
Fixed C# Header Implementation
Instead of messing with string concatenation, build the header directly as a byte array (this is far more reliable for binary protocols):
private byte[] BuildHeader(byte[] command, short length) { // CIP encapsulation header is fixed 24 bytes byte[] header = new byte[24]; int offset = 0; // Command (2-byte UINT, big-endian) if (command.Length != 2) throw new ArgumentException("Command must be 2 bytes"); if (BitConverter.IsLittleEndian) Array.Reverse(command); // Convert to big-endian if needed Array.Copy(command, 0, header, offset, 2); offset += 2; // Length (2-byte UINT, big-endian) byte[] lengthBytes = BitConverter.GetBytes(length); if (BitConverter.IsLittleEndian) Array.Reverse(lengthBytes); Array.Copy(lengthBytes, 0, header, offset, 2); offset += 2; // Session Handle (4-byte UDINT, big-endian) byte[] sessionBytes = BitConverter.GetBytes(SessionID); if (BitConverter.IsLittleEndian) Array.Reverse(sessionBytes); Array.Copy(sessionBytes, 0, header, offset, 4); offset += 4; // Status (4-byte UDINT, all zeros) // Skip—already initialized to 0 offset += 4; // Sender Context (8-byte field) // Ensure Context is a 64-bit value (long) to fill the 8-byte field byte[] contextBytes = BitConverter.GetBytes(Context); if (BitConverter.IsLittleEndian) Array.Reverse(contextBytes); Array.Copy(contextBytes, 0, header, offset, 8); offset += 8; // Option (4-byte UDINT, all zeros) // Skip—already initialized to 0 return header; }
Additional Notes
- Verify Command Bytes: Ensure your
commandbyte array is 2 bytes (e.g.,0x0000for List Services,0x0001for Register Session) and adjusted to big-endian order. - Session ID: After receiving the Register Session response, update
SessionIDwith the 4-byte value from the response (convert from big-endian to host byte order if needed). - Context Field: Change your C#
Contextvariable to along(64-bit integer) to match the 8-byte Sender Context field requirement. - Sending the Header: When sending data, combine the header byte array with your command payload (if any) and send the entire buffer via
Socket.Send()—avoid converting to a string at any point.
This fixes the structural issues in your header, which should resolve the "Unsupported encapsulation protocol revision" error. PLCs are strict about adhering to exact protocol formats, so even small byte mismatches will trigger this kind of rejection.
内容的提问来源于stack exchange,提问作者Belekz

