奇怪的SNMP移位操作

3
下面是来自 Richard Blum 的《C# 网络编程》一书中的内容:
public byte[] get(string request, string host, string community, string_ mibstring)
{
    byte[] packet = new byte[1024];
    byte[] mib = new byte[1024];
    int snmplen;
    int comlen = community.Length;
    string[] mibvals = mibstring.Split('.');
    int miblen = mibvals.Length;
    int cnt = 0, temp, i;
    int orgmiblen = miblen;
    int pos = 0;
    // Convert the string MIB into a byte array of integer values
    // Unfortunately, values over 128 require multiple bytes
    // which also increases the MIB length
    for (i = 0; i < orgmiblen; i++)
    {
        temp = Convert.ToInt16(mibvals[i]);
        if (temp > 127)
        {
            mib[cnt] = Convert.ToByte(128 + (temp / 128));
            mib[cnt + 1] = Convert.ToByte(temp - ((temp / 128) * 128));
            cnt += 2;
            miblen++;
        } 
        else
        {
        mib[cnt] = Convert.ToByte(temp);
        cnt++;
        }
    }
    snmplen = 29 + comlen + miblen - 1; //Length of entire SNMP packet
    //The SNMP sequence start
    packet[pos++] = 0x30; //Sequence start
    packet[pos++] = Convert.ToByte(snmplen - 2); //sequence size
    //SNMP version
    packet[pos++] = 0x02; //Integer type
    packet[pos++] = 0x01; //length
    packet[pos++] = 0x00; //SNMP version 1
    //Community name
    packet[pos++] = 0x04; // String type
    packet[pos++] = Convert.ToByte(comlen); //length
    //Convert community name to byte array
    byte[] data = Encoding.ASCII.GetBytes(community);
    for (i = 0; i < data.Length; i++)
    {
        packet[pos++] = data[i];
    }
}

我不明白下面的代码:

    for (i = 0; i < orgmiblen; i++)
    {
        temp = Convert.ToInt16(mibvals[i]);
        if (temp > 127)
        {
            mib[cnt] = Convert.ToByte(128 + (temp / 128));
             mib[cnt + 1] = Convert.ToByte(temp - ((temp / 128) * 128));
             cnt += 2;
             miblen++;
        } 
        else
        {
            mib[cnt] = Convert.ToByte(temp);
            cnt++;
        }
    }

我理解这是将临时变量转换为两个字节,如果临时变量超过一个字节大小。但是,128+(temp/128)的计算是什么意思?然后对于第二个字节:temp-(temp/128)* 128,这就是我不明白的地方。

请帮忙解释一下,谢谢。


为什么点赞?能解释一下吗? - Voice
这绝对不是从int到bytes的标准转换。它一定是SNMP协议中特定的某些东西,或者只是简单的胡言乱语。它看起来很奇怪,有两个原因:(1)一个字节可以容纳高达255的值。为什么需要特殊处理127以上的所有内容(而不是注释所说的128)是不清楚的。(2)将整数拆分为其字节部分通常使用位移操作完成。(3)即使这种拆分的原因是协议仅支持范围从-128到127的有符号字节,该转换也毫无意义,因为它将导致(cont) - Daniel Hilgarth
在第一个字节中,数值大于127的(请参见Eoin Campbell的示例计算)。 - Daniel Hilgarth
@Voice: a) 因为这个问题写得很好。他包含了完整的代码,以便您可以了解情况,然后是他遇到问题的部分以及他理解和不理解的解释。b) 因为这段代码使用了奇怪的移位解决方案。 - jgauffin
3个回答

3

如果temp大于127,则需要用两个字节来表示。让我们看两个例子:

temp = 100;
128 + (temp / 128); //(temp / 128) = 0 + 128 so the mib[cnt] is set to 128
temp - ((temp/128) * 128); // 0*128 = 0. subtracted from temp leaves the original. so you end up with

mib[cnt] = 128;
mib[cnt+1] = 100;

现在,如果temp的值大于127。
temp = 200;
128 + (temp / 128); //(temp / 128) = 1 + 128 so the mib[cnt] is set to 129
temp - ((temp/128) * 128); // 1*128 = 128. 200-128 = 72. so you end up with

mib[cnt] = 129;
mib[cnt+1] = 72;

基本上,它会取一个数字,测试它是否大于7个字节(-128 => +127是一个有符号字节),如果您提供的数字超出了该范围,它会将其转换为2个字节的值。


你能解释一下两个字节的 12972 是如何表示 200 的吗?无论是 AND 还是 OR 都不会得到 200。此外,129 仍然超过了有符号字节的最大值 127。 - Daniel Hilgarth
我猜这与SNMP协议有关。128的二进制=“1000 0000”,但你不能用一个字节存储128,因为它会溢出。所以我猜它把最高有效位作为正负号值处理。int = 100的评估为“1000 0000 0110 0100”。int = 200的评估为“1000 0001 0100 1000”。所以如果你只丢弃那个最左边的数位,它将被评估为2字节(word)值。 - Eoin Campbell
1000 0001解释为有符号字节会得到-127。加上72的结果是-55... - Daniel Hilgarth
我同意。我并不是说这样做有意义,只是代码似乎是这么做的。我不知道为什么他要以那种方式切换最左边的有效位,因为正如你所指出的,那似乎会抵消该值。 - Eoin Campbell
2
如果你手头恰好有《理解SNMP MIB》这本书,你可以在第394页A.5.4上找到解释。切换的比特用于指示多八位子标识符。 - Lex Li
显示剩余2条评论

1
以下摘自《理解SNMP MIBs》第394页,因为这本书比其他任何书都更好地描述了技术细节,
编码的OBJECT IDENTIFIER由原始值中的每个子标识符编码和串联而成。每个子标识符都被编码为一系列八位字节,具体如下:
- 每个八位字节的第8位表示它是否是子标识符的最后一个八位字节,通过将此位设置为0来实现。 - 八位字节中的第7到第1位(串联在一起)形成子标识符的值。 - 子标识符中的第一个八位字节可能没有值80(十六进制)。这确保使用最少数量的八位字节进行编码。值80(十六进制)表示还有更多的八位字节,但值位(7-1)设置为零。
实际上,在问题正文中粘贴的源代码遵循了解析字节的规则。因此,如果您了解规则,就可以理解代码。
(更新:这些规则来自ITU-T X.690, ISO/IEC 8825-1。)

非常感谢您的帮助,我只是好奇 - 我找不到那本书,所以开始在互联网上搜索,并发现了一篇工程论文,在其中他用David Perkins的话在文档的第12页(pdf第23页)描述了相同的内容:这是链接:http://etd.lib.fsu.edu/theses/available/etd-11102008-191830/unrestricted/VollmerDThesis.pdf。我很高兴像您这样的人能够提供帮助。我现在完全理解那段代码,并正在开发自己的解决方案。 - user726720

-1

这适用于所有值:

        for (i = 0; i < orgmiblen; i++)
        {
            temp = Convert.ToInt64(mibvals[i]);
            int k = (int)Math.Log((Double)temp, (Double)2) / 7;
            miblen += k;
            int continuation = 0;
            do
            {
                mib[cnt++ + k] = Convert.ToByte((temp & 127) + continuation);
                temp = ((int)(temp / 128));
                continuation = 128;
                k -= 2;
            }
            while (temp > 0);
        }

1
-1 你没有回答问题。他想要了解为什么代码看起来是那样的。 - jgauffin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接