【Web前端问题】关于 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
*/
static RadiusPacket decodePacket(Dictionary dictionary, InputStream in, String sharedSecret, RadiusPacket request)
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.
以上是 【Web前端问题】关于 java 位运算 的全部内容, 来源链接: utcz.com/a/143516.html