如何从Java中的字节[]计算internet校验和
我正试图弄明白如何用Java计算互联网校验和,这给我带来了无尽的痛苦。(我对位操作很糟糕。)我在C#中找到了一个版本。然而,我试图将其转换为Java,却没有看到正确的结果。有人能看出我做错了什么吗?我怀疑有数据类型问题如何从Java中的字节[]计算internet校验和,java,checksum,ip-protocol,Java,Checksum,Ip Protocol,我正试图弄明白如何用Java计算互联网校验和,这给我带来了无尽的痛苦。(我对位操作很糟糕。)我在C#中找到了一个版本。然而,我试图将其转换为Java,却没有看到正确的结果。有人能看出我做错了什么吗?我怀疑有数据类型问题 public long getValue() { byte[] buf = { (byte) 0xed, 0x2A, 0x44, 0x10, 0x03, 0x30}; int length = buf.length; int i = 0; lon
public long getValue() {
byte[] buf = { (byte) 0xed, 0x2A, 0x44, 0x10, 0x03, 0x30};
int length = buf.length;
int i = 0;
long sum = 0;
long data = 0;
while (length > 1) {
data = 0;
data = (((buf[i]) << 8) | ((buf[i + 1]) & 0xFF));
sum += data;
if ((sum & 0xFFFF0000) > 0) {
sum = sum & 0xFFFF;
sum += 1;
}
i += 2;
length -= 2;
}
if (length > 0) {
sum += (buf[i] << 8);
// sum += buffer[i];
if ((sum & 0xFFFF0000) > 0) {
sum = sum & 0xFFFF;
sum += 1;
}
}
sum = ~sum;
sum = sum & 0xFFFF;
return sum;
}
public long getValue(){
字节[]buf={(字节)0xed,0x2A,0x44,0x10,0x03,0x30};
int length=buf.length;
int i=0;
长和=0;
长数据=0;
而(长度>1){
数据=0;
数据=((buf[i])0){
sum=sum&0xFFFF;
总和+=1;
}
i+=2;
长度-=2;
}
如果(长度>0){
总和+=(buf[i]0){
sum=sum&0xFFFF;
总和+=1;
}
}
sum=~sum;
sum=sum&0xFFFF;
回报金额;
}
我认为是类型升级造成了麻烦。让我们看看数据=((buf[I])编辑后应用@Andy、@EJP、@RD等人的评论,并添加额外的测试用例,以确保这一点
我使用了@Andys-answer(正确识别问题的位置)的组合,并更新了代码,以包括链接答案中提供的单元测试以及附加测试用例
首先是实施
package org.example.checksum;
public class InternetChecksum {
/**
* Calculate the Internet Checksum of a buffer (RFC 1071 - http://www.faqs.org/rfcs/rfc1071.html)
* Algorithm is
* 1) apply a 16-bit 1's complement sum over all octets (adjacent 8-bit pairs [A,B], final odd length is [A,0])
* 2) apply 1's complement to this final sum
*
* Notes:
* 1's complement is bitwise NOT of positive value.
* Ensure that any carry bits are added back to avoid off-by-one errors
*
*
* @param buf The message
* @return The checksum
*/
public long calculateChecksum(byte[] buf) {
int length = buf.length;
int i = 0;
long sum = 0;
long data;
// Handle all pairs
while (length > 1) {
// Corrected to include @Andy's edits and various comments on Stack Overflow
data = (((buf[i] << 8) & 0xFF00) | ((buf[i + 1]) & 0xFF));
sum += data;
// 1's complement carry bit correction in 16-bits (detecting sign extension)
if ((sum & 0xFFFF0000) > 0) {
sum = sum & 0xFFFF;
sum += 1;
}
i += 2;
length -= 2;
}
// Handle remaining byte in odd length buffers
if (length > 0) {
// Corrected to include @Andy's edits and various comments on Stack Overflow
sum += (buf[i] << 8 & 0xFF00);
// 1's complement carry bit correction in 16-bits (detecting sign extension)
if ((sum & 0xFFFF0000) > 0) {
sum = sum & 0xFFFF;
sum += 1;
}
}
// Final 1's complement value correction to 16-bits
sum = ~sum;
sum = sum & 0xFFFF;
return sum;
}
}
较短的版本如下所示:
long checksum(byte[] buf, int length) {
int i = 0;
long sum = 0;
while (length > 0) {
sum += (buf[i++]&0xff) << 8;
if ((--length)==0) break;
sum += (buf[i++]&0xff);
--length;
}
return (~((sum & 0xFFFF)+(sum >> 16)))&0xFFFF;
}
长校验和(字节[]buf,整数长度){
int i=0;
长和=0;
而(长度>0){
sum+=(buf[i++]&0xff>16))&0xFFFF;
}
感谢额外的单元测试。关于我的代码是否由于一些错误的测试而不正确,我得到了相互矛盾的答案。@chotchki我已经编辑了答案,以包含来自@Andy et al的注释为什么calculateChecksum
返回长值?UDP、TCP和IPv4校验和需要两个字节。所以int(最多4个字节)应该是足够的代码是根据RFC1071第4.1节中的示例修改的,该示例使用了long作为其和。在编写RFC时,long可能是32位。这在很大程度上与避免Java中的类型升级有关。有关更多详细信息,请查看其他答案(@Andy现在是@Andrey Balaguta)#2不正确。文本0xFF被视为int,而不是字节。在步骤#3中,您将有一个短的| int,其中第一个参数得到提升,而不是第二个参数。因此,问题不在于您的示例中的0x00,0xFF,而在于0xFF、0x00(或任何buf[i]>0x7F)。当第一个参数从short扩展到int时,它是符号扩展的,正如您所解释的。在原始程序中,是0xed,0x2A的情况导致校验和不正确。这篇文章是非常不正确的。#1,#2和#3的结果是int,除非其中任何一个参数是long,在这种情况下它是long。en轮胎表达式类似于一个int,当存储在一个int中时,它会被加宽到一个long。@RD:老实说,我不知道如何解决这个问题。@EJP,@RD,谢谢你的更正,很抱歉误导。我已经相应地更正了帖子。它是符号扩展,不是“符号扩展”。我喜欢你的版本,但
long checksum(byte[] buf, int length) {
int i = 0;
long sum = 0;
while (length > 0) {
sum += (buf[i++]&0xff) << 8;
if ((--length)==0) break;
sum += (buf[i++]&0xff);
--length;
}
return (~((sum & 0xFFFF)+(sum >> 16)))&0xFFFF;
}