解码字节数组
Decode byte array
我想解码从 modbus 通信接收到的字节数组。这是表示字节数组的十六进制字符串:
01 11 0C 46 57 35 32 39 37 30 31 52 30 2E 35 FE 27
我想分成三部分:
- 01 11 0C
- 46 57 35 32 39 37 30 31 52 30 2E 35
- FE 27
为了从字节转换为十六进制,我使用了这个方法:
#region ByteToHex
/// <summary>
/// method to convert a byte array into a hex string
/// </summary>
/// <param name="comByte">byte array to convert</param>
/// <returns>a hex string</returns>
public string ByteToHex(byte[] comByte)
{
//create a new StringBuilder object
StringBuilder builder = new StringBuilder(comByte.Length * 3);
//loop through each byte in the array
foreach (byte data in comByte)
//convert the byte to a string and add to the stringbuilder
builder.Append(Convert.ToString(data, 16).PadLeft(2, '0').PadRight(3, ' '));
//return the converted value
return builder.ToString().ToUpper();
}
如何将 returned 字符串从该方法拆分为 return:
前 3 个字节是:
- 服务器编号
- 函数代码
- 字节数
接下来的N个字节(见3.)是载荷;最后 2 个是 CRC16。
我需要找到负载;它是一个字符串。
string str = ByteToHex(comByte);
string partOne = str.Substring(0, 8);
string partTwo = str.Substring(9, 35);
string partThree = str.Substring(45, 5);
部分答案:
如果返回的字节表示结构化数据,您应该不将所有字节转换为字符串。而是根据字节的含义转换字节:
int serverId = Convert.ToInt32(byte[0]);
int functionCode = Convert.ToInt32(byte[1]);
int byteCount = Convert.ToInt32(byte[2]);
一旦你知道了数据部分的长度,你就可以解码这个数据:
for(int i = 0; i < byteCount; i++)
{
// do something with byte[3+i]
}
首先更改现有 ByteToHex
方法的签名,使输入参数为 IEnumerable<byte>
而不是 byte[]
。
然后使用:
var str1 = ByteToHex(new ArraySegment<byte>(yourBytes, 0, 3));
var str2 = ByteToHex(new ArraySegment<byte>(yourBytes, 3, 12));
var str3 = ByteToHex(new ArraySegment<byte>(yourBytes, 15, 2));
自 .NET 4.5(Visual Studio 2012)起可以使用 ArraySegment<>
。
PS!可以简化方法的整个主体:
public static string ByteToHex(IEnumerable<byte> comByte)
{
return string.Join(" ", comByte.Select(b => b.ToString("X2")));
}
这里的大写 X
表示十六进制格式,大写 "digits" A 到 F, 2
表示用零填充长度为 2。
如果要拆分字节数组,请直接在数组上进行 - 不要事先转换为字符串!生成的代码将更容易理解。
之后您仍然可以将它的一部分转换为十六进制字符串,或者在您的情况下转换为带有编码而不是十六进制的文本字符串。
对于子数组,我有这个小扩展:
// Returns the SubArray starting from index and covering the amount of length items.
public static T[] SubArray<T>(this T[] data, int index, int length)
{
T[] result = new T[length];
System.Array.Copy(data, index, result, 0, length);
return result;
}
正如另一个答案中提到的那样,自 .NET 4.5 以来,您也可以改用新的 ArraySegment。
有了这个,你可以像这样简单地拆分:
const int HEADER_LENGTH = 3; //1 Byte ServerId, 1 Byte Function Code, 1 Byte ByteCount
const int CRC_LENGTH = 2;
var bytes = new byte[]{0x01, 0x11, 0x0C, 0x46, 0x57, 0x35, 0x32, 0x39, 0x37, 0x30, 0x31, 0x52, 0x30, 0x2E, 0x35, 0xFE, 0x27};
int payloadLength = bytes.Count() - HEADER_LENGTH - CRC_LENGTH;
//.NET 4.5 solution
var textbytes = new ArraySegment<byte>(bytes, HEADER_LENGTH, payloadLength).ToArray();
//pre 4.5 solution with extension
var textbytes = bytes.SubArray(HEADER_LENGTH, payloadLength);
var text = Encoding.ASCII.GetString(textbytes); //FW529701R0.5
将输入转为十六进制字符串意义不大。您需要解码字节包含的信息。他们持有的内容完全取决于您只是解释的文档。我会试一试:
public class ModbusRequest
{
public byte ServerId { get; set; }
public byte FunctionCode { get; set; }
public string Payload { get; set; }
}
public ModbusRequest DecodeMessage(byte[] message)
{
var result = new ModbusRequest();
// Simply copy bytes 0 and 1 into the destination structure.
result.ServerId = message[0];
result.FunctionCode = message[1];
byte stringLength = message[2];
// Assuming ASCII encoding, see docs.
result.Payload = Encoding.ASCII.GetString(message, 3, stringLength);
// Get the CRC bytes.
byte[] crc = new byte[2];
Buffer.BlockCopy(message, 4 + stringLength, crc, 0, 2);
// TODO: verify CRC.
return result;
}
要验证 CRC,找出正在使用的格式。我建议使用 classless-hasher 来实现各种 CRC 变体。
我想解码从 modbus 通信接收到的字节数组。这是表示字节数组的十六进制字符串:
01 11 0C 46 57 35 32 39 37 30 31 52 30 2E 35 FE 27
我想分成三部分:
- 01 11 0C
- 46 57 35 32 39 37 30 31 52 30 2E 35
- FE 27
为了从字节转换为十六进制,我使用了这个方法:
#region ByteToHex
/// <summary>
/// method to convert a byte array into a hex string
/// </summary>
/// <param name="comByte">byte array to convert</param>
/// <returns>a hex string</returns>
public string ByteToHex(byte[] comByte)
{
//create a new StringBuilder object
StringBuilder builder = new StringBuilder(comByte.Length * 3);
//loop through each byte in the array
foreach (byte data in comByte)
//convert the byte to a string and add to the stringbuilder
builder.Append(Convert.ToString(data, 16).PadLeft(2, '0').PadRight(3, ' '));
//return the converted value
return builder.ToString().ToUpper();
}
如何将 returned 字符串从该方法拆分为 return: 前 3 个字节是:
- 服务器编号
- 函数代码
- 字节数
接下来的N个字节(见3.)是载荷;最后 2 个是 CRC16。
我需要找到负载;它是一个字符串。
string str = ByteToHex(comByte);
string partOne = str.Substring(0, 8);
string partTwo = str.Substring(9, 35);
string partThree = str.Substring(45, 5);
部分答案:
如果返回的字节表示结构化数据,您应该不将所有字节转换为字符串。而是根据字节的含义转换字节:
int serverId = Convert.ToInt32(byte[0]);
int functionCode = Convert.ToInt32(byte[1]);
int byteCount = Convert.ToInt32(byte[2]);
一旦你知道了数据部分的长度,你就可以解码这个数据:
for(int i = 0; i < byteCount; i++)
{
// do something with byte[3+i]
}
首先更改现有 ByteToHex
方法的签名,使输入参数为 IEnumerable<byte>
而不是 byte[]
。
然后使用:
var str1 = ByteToHex(new ArraySegment<byte>(yourBytes, 0, 3));
var str2 = ByteToHex(new ArraySegment<byte>(yourBytes, 3, 12));
var str3 = ByteToHex(new ArraySegment<byte>(yourBytes, 15, 2));
自 .NET 4.5(Visual Studio 2012)起可以使用 ArraySegment<>
。
PS!可以简化方法的整个主体:
public static string ByteToHex(IEnumerable<byte> comByte)
{
return string.Join(" ", comByte.Select(b => b.ToString("X2")));
}
这里的大写 X
表示十六进制格式,大写 "digits" A 到 F, 2
表示用零填充长度为 2。
如果要拆分字节数组,请直接在数组上进行 - 不要事先转换为字符串!生成的代码将更容易理解。
之后您仍然可以将它的一部分转换为十六进制字符串,或者在您的情况下转换为带有编码而不是十六进制的文本字符串。
对于子数组,我有这个小扩展:
// Returns the SubArray starting from index and covering the amount of length items.
public static T[] SubArray<T>(this T[] data, int index, int length)
{
T[] result = new T[length];
System.Array.Copy(data, index, result, 0, length);
return result;
}
正如另一个答案中提到的那样,自 .NET 4.5 以来,您也可以改用新的 ArraySegment。
有了这个,你可以像这样简单地拆分:
const int HEADER_LENGTH = 3; //1 Byte ServerId, 1 Byte Function Code, 1 Byte ByteCount
const int CRC_LENGTH = 2;
var bytes = new byte[]{0x01, 0x11, 0x0C, 0x46, 0x57, 0x35, 0x32, 0x39, 0x37, 0x30, 0x31, 0x52, 0x30, 0x2E, 0x35, 0xFE, 0x27};
int payloadLength = bytes.Count() - HEADER_LENGTH - CRC_LENGTH;
//.NET 4.5 solution
var textbytes = new ArraySegment<byte>(bytes, HEADER_LENGTH, payloadLength).ToArray();
//pre 4.5 solution with extension
var textbytes = bytes.SubArray(HEADER_LENGTH, payloadLength);
var text = Encoding.ASCII.GetString(textbytes); //FW529701R0.5
将输入转为十六进制字符串意义不大。您需要解码字节包含的信息。他们持有的内容完全取决于您只是解释的文档。我会试一试:
public class ModbusRequest
{
public byte ServerId { get; set; }
public byte FunctionCode { get; set; }
public string Payload { get; set; }
}
public ModbusRequest DecodeMessage(byte[] message)
{
var result = new ModbusRequest();
// Simply copy bytes 0 and 1 into the destination structure.
result.ServerId = message[0];
result.FunctionCode = message[1];
byte stringLength = message[2];
// Assuming ASCII encoding, see docs.
result.Payload = Encoding.ASCII.GetString(message, 3, stringLength);
// Get the CRC bytes.
byte[] crc = new byte[2];
Buffer.BlockCopy(message, 4 + stringLength, crc, 0, 2);
// TODO: verify CRC.
return result;
}
要验证 CRC,找出正在使用的格式。我建议使用 classless-hasher 来实现各种 CRC 变体。