首页 > 关于 java 位运算

关于 java 位运算

这段代码中和0x0ff与运算是什么意思? 获取length的原理是什么?
其中对象in如下


// read and check header 
int type = in.read() & 0x0ff;
int identifier = in.read() & 0x0ff;
int length = (in.read() & 0x0ff) << 8 | (in.read() & 0x0ff);

所有的代码

/**
    • Reads a Radius packet from the given input stream and

    • creates an appropiate RadiusPacket descendant object.

    • Reads in all attributes and returns the object.

    • Decodes the encrypted fields and attributes of the packet.

    • @param dictionary dictionary to use for attributes

    • @param sharedSecret shared secret to be used to decode this packet

    • @param request Radius request packet if this is a response packet to be

    • decoded, null if this is a request packet to be decoded

    • @return new RadiusPacket object

    • @exception IOException if an IO error occurred

    • @exception RadiusException if the Radius packet is malformed
      */

    1. static RadiusPacket decodePacket(Dictionary dictionary, InputStream in, String sharedSecret, RadiusPacket request)

    2. IOException, RadiusException {

         // check shared secret
         if (sharedSecret == null || sharedSecret.length() == 0)
             throw new RuntimeException("no shared secret has been set");
      
         // check request authenticator
         if (request != null && request.getAuthenticator() == null)
             throw new RuntimeException("request authenticator not set");
      
         // read and check header
         int type = in.read() & 0x0ff;
         int identifier = in.read() & 0x0ff;
         int length = (in.read() & 0x0ff) << 8 | (in.read() & 0x0ff);
      
         if (request != null && request.getPacketIdentifier() != identifier)
             throw new RadiusException("bad packet: invalid packet identifier (request: " + request.getPacketIdentifier() + ", response: " + identifier);
         if (length < RADIUS_HEADER_LENGTH)
             throw new RadiusException("bad packet: packet too short (" + length + " bytes)");
         if (length > MAX_PACKET_LENGTH)
             throw new RadiusException("bad packet: packet too long (" + length + " bytes)");
      
         // read rest of packet
         byte[] authenticator = new byte[16];
         byte[] attributeData = new byte[length - RADIUS_HEADER_LENGTH];
         in.read(authenticator);
         in.read(attributeData);
      
         // check and count attributes
         int pos = 0;
         int attributeCount = 0;
         while (pos < attributeData.length) {
             if (pos + 1 >= attributeData.length)
                 throw new RadiusException("bad packet: attribute length mismatch");
             int attributeLength = attributeData[pos + 1] & 0x0ff;
             if (attributeLength < 2)
                 throw new RadiusException("bad packet: invalid attribute length");
             pos += attributeLength;
             attributeCount++;
         }
         if (pos != attributeData.length)
             throw new RadiusException("bad packet: attribute length mismatch");
      
         // create RadiusPacket object; set properties
         RadiusPacket rp = createRadiusPacket(type);
         rp.setPacketType(type);
         rp.setPacketIdentifier(identifier);
         rp.authenticator = authenticator;
         
         // load attributes
         pos = 0;
         while (pos < attributeData.length) {
             int attributeType = attributeData[pos] & 0x0ff;
             int attributeLength = attributeData[pos + 1] & 0x0ff;
             RadiusAttribute a = RadiusAttribute.createRadiusAttribute(dictionary, -1, attributeType);
             a.readAttribute(attributeData, pos, attributeLength);
             rp.addAttribute(a);
             pos += attributeLength;
         }
         
         // request packet?
         if (request == null) {
             // decode attributes
             rp.decodeRequestAttributes(sharedSecret);
             rp.checkRequestAuthenticator(sharedSecret, length, attributeData);
         } else {
             // response packet: check authenticator
             rp.checkResponseAuthenticator(sharedSecret, length, attributeData, request.getAuthenticator());
         }
         
         return rp;

      }


    0x0ff 就是

    0000 0000 1111 1111
    

    一个数字和 0x0ff 进行运算,则会把高8位置0,低8位保留


    回到你的程序中,通过这个函数猜测应该是解析的 RFC2866 报文:

    报文格式:

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |     Code      |  Identifier   |            Length             |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                                                               |
    |                         Authenticator                         |
    |                                                               |
    |                                                               |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |  Attributes ...
    +-+-+-+-+-+-+-+-+-+-+-+-+-
    

    根据格式, 0-7位是 CODE 信息,在你的函数中用 type 存储。(注意 type 的类型,是 int)

    @brayden 提到了,InputStream.read() 一个读一个 byte,正好是 8 位,所以,如果写 byte type = in.read() 就正好了。但是 type 的类型是 int,因此我们需要处理一下。

    如果我们读入的是 5,那么当我们把他转换成 int 时,也应该是 5。那么需要在前面添加 0。

                0000 0101
    & 0000 0000 1111 1111
    -------------------------------
      0000 0000 0000 0101
    

    同理,读报文的 8-15位。

    length 的值比较难读取,因为它一共16位,而 in.read() 每次只能读8个字节,那么就需要读取两次,然后拼凑。方法是,先读8位,然后左移,再读8位。

    int length = (in.read() & 0x0ff) << 8 | (in.read() & 0x0ff);
    

    java里InputStream.read()一个读一个byte, 但是返回一个int, 四字节; 但实际上有用的只是最后的那个byte. 所以需要每次in.read() & 0x0ff;

    具体到这段代码, 读第一个byte到一个int型, 赋值给type; 读第二个byte到一个int型, 赋值给identifier; 读第三个byte, 第四个byte, 第三个字节左移8位, 和第四个字节拼接起来, 赋值给length.

    【热门文章】
    【热门文章】