中固定头部中byte2 标识包的剩余长度, 单个byte最大能表示127的包长度,最高为标识位,1代表借用后续字节来标识包长度。
Table 1‑1 Size of Variable Byte Integer
Digits | From | To |
1 | 0 (0x00) | 127 (0x7F) |
2 | 128 (0x80, 0x01) | 16,383 (0xFF, 0x7F) |
3 | 16,384 (0x80, 0x80, 0x01) | 2,097,151 (0xFF, 0xFF, 0x7F) |
4 | 2,097,152 (0x80, 0x80, 0x80, 0x01) | 268,435,455 (0xFF, 0xFF, 0xFF, 0x7F) |
协议文档给出了算法如下:
The algorithm for encoding a non-negative integer (X) into the Variable Byte Integer encoding scheme is as follows:
do
encodedByte = X MOD 128
X = X DIV 128
// if there are more data to encode, set the top bit of this byte
if (X > 0)
encodedByte = encodedByte OR 128
endif
'output' encodedByte
while (X > 0)
Where MOD is the modulo operator (% in C), DIV is integer division (/ in C), and OR is bit-wise or (| in C).
The algorithm for decoding a Variable Byte Integer type is as follows:
multiplier = 1
value = 0
do
encodedByte = 'next byte from stream'
value += (encodedByte AND 127) * multiplier
if (multiplier > 128*128*128)
throw Error(Malformed Variable Byte Integer)
multiplier *= 128
while ((encodedByte AND 128) != 0)
where AND is the bit-wise and operator (& in C).
When this algorithm terminates, value contains the Variable Byte Integer value.
利用C# 来写为:
private void btn10toHex_Click(object sender, EventArgs e)
{
try
{
int num = int.Parse(this.txtDeciValue.Text);
byte[] bytes = ConvertLength2MqttByte(num);
string result= BytesConverter.ToHexString(bytes);
this.txtHexValueCvt.Text = result;
this.txtHexValue.Text = result;
}
catch { }
}
/// <summary>
/// 把给定长度转成Mqtt 固定头部剩余长度字节
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
byte[] ConvertLength2MqttByte(int length)
{
try
{
int encodeByte = 0;//需编码输出的数
int dec = 128;//进制数,二进制为 1000 0000
int reminder = length;
do
{
//取num 的结束字节,高1位是符号位
int lastEncodeByte = reminder % dec;
reminder = reminder / dec;// 取余数
if (reminder > 0)//需向高位进位
{
lastEncodeByte |= dec;// 高位符号位 填充1
lastEncodeByte <<= 8;
encodeByte <<= 8;//左移动8位,留给低字节
}
encodeByte |= lastEncodeByte;//填充低字节
} while (reminder > 0);
byte[] bytes = BitConverter.GetBytes(encodeByte);
Array.Reverse(bytes);
List<byte> targetBytes = new List<byte>();
targetBytes.AddRange(bytes);
var outputArray = targetBytes.Where(x => x > 0);
return outputArray.ToArray();
}
catch
{
return null;
}
}
/// <summary>
/// 把MQTT 剩余长度的16进制格式转化对应的10进制数值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnHexTo10_Click(object sender, EventArgs e)
{
try
{
string[] hexRaw = this.txtHexValue.Text.Split(' ');//低位在前
int result = 0;
for (int i = 0; i <hexRaw.Length; i++)
{
int mutiplier = 1;
for (int j = 0; j < i; j++)
{
mutiplier *= 128;
}
byte num = Convert.ToByte(hexRaw[i], 16);
byte temp = (byte)(num << 1);
byte leftNum = (byte)(temp >> 1);
result += leftNum * mutiplier;
}
this.txtDeciCvt.Text = result.ToString();
}
catch
{ }
}