IP包的首部校验和的计算与程序设计
一,感受与实验基本要求
这是我《计算机网络》这门课程的第二个实验,说实话这个实验吧,我觉得我完成的不是特别的好,好些地方都是取巧,并不是真正意义上的完成这个实验。但是我觉得还是把这个实验的前后写下来,毕竟是见证自己的一个成长。接下来我会先介绍一下实验要求与实验内容。
1.1 实验目的
1.掌握IP协议包结构;
2.学会IP协议包首部数据校验
1.2 实验要求
针对 IP 协议包结构,2 人一组,共同设计良好的人机界面,并实现首部校验和的计算程序。功能包括:
(1)在界面上,用户能够输入或编辑 IP 协议包各字段数据,例如,“协议”字段应该是下拉选择 方式;
(2)程序能够自动检查 IP 地址的合法性,且主机可用;
(3)能够自动计算首部校验和的值,并显示计算结果;
(4)必须验证程序的正确性:基于 Wireshark 工具所抓取的真实 IP 包首部数据,能够成功检验首 部校验和字段的计算程序。
二,实验内容
2.1 IP首部的基本校验方法
1,把IP数据包的校验和字段置为0;
2,把首部看成以16位为单位的数字组成,依次进行二进制求和(注意:求和时应将最高位的进位保存,所以加法应采用32位加法);
3,将上述加法过程中产生的进位(最高位的进位)加到低16位(采用32位加法时,即为将高16位与低16位相加,之后还要把该次加法最高位产生的进位加到低16位)
4,将上述的和取反,即得到校验和。
2.2流程图
2.3编程思路
2.3.1得到数据并进行标准化
首先,程序需要从交互界面获取十进制表示的IP头除了校验和的各部分数据。将这些数据转换成16进制形式的字符串,进行标准化,若不进行标准化,则容易在不同信息合并中因为结束出现问题。
String type1 = Edition.getSelectedItem();//获取所选内容
String HeadLength1 = HeadLength.getText();//获取文本框内的内容
String SeverType1 = SeverType.getSelectedItem();//下拉框的
SeverType1 = flags_change(SeverType1);
Sum[0] = Integer.parseInt(Connecting(type1,HeadLength1,SeverType1),16);//将版本,首部长度与服务结合,形成sum1。
如上,采集下拉框Edition(版本)(使用getSelectedItem()函数)、SeverType(服务类型)与文本框HeadLength(头部长度)(使用getText()函数)的填入字符串,然后通过Connecting()函数将字符串拼接起来,并通过parseInt()内置函数将其转换成16进制存储在sum[]数组中。
采集
String S_IP1 = Length(encodeHEX(Integer.parseInt(S_IP_add1.getText())));
标准化函数
public static String Length(String a) {
String b = null;
if(a.length()==1) b = "0" + a;
else if(a.length() == 2) b = a;
return b;
}
是采集IP地址的第一个框的内容,而Length()的作用是标准化,将其表标准化为“xx”的形式,方便后面的拼接操作。
2.3.2 信息合并后,把字符串转换成十进制,并存储在数组中。
String AllLength2 = encodeHEX(Integer.parseInt(AllLength1));
将两个IP的范围的16进制形式通过Connecting()函数连接,通过parseInt(String,16)转化成10进制的int型,并存储在数组Sum[]中。
parseInt(String,16)
的作用是把以字符串形式存储的16进制转换成10进制的整形。
public String Connecting(String a,String b,String c) {
//将首部连接
String d;
if(c != null) {
d = a+b+c;
}else {
d = a+b;
}
return d;
}
看这个函数,可以决定是连接多少个首部,并存储在字符串中。
2.3.3 进行求和运算。用循环方式对数组内的10进制进行求和,并转换成字符串形式的16进制。
String SUM = count(Sum);
这是对Sum数组进行求和运算,Sum是一个数组,里面存着首部除了校验和之外的全部信息的十进制形式。
//先用10进制首部校验求和,然后转化成16进制
public static String count(int[] a) {
int sum = 0;
String end;
for(int i = 0;i < 9;i++) {
sum += a[i];
}
end = encodeHEX(sum);
return end;
}
为count()函数内部图,利用for循环将数组内部的10进制数字求和。这里返回的是和的16进制形式。
2.3.4 判断是否产生溢出,若产生溢出,依次将最高位的数字加在低位上,直到满足4位的16进制。
if(SUM.length()>4) {
//若字长大于4位,则进行进位,将最高位加到最低位
String s = SUM.substring(SUM.length()-4);
String a = SUM.substring(0,1);
int i = Integer.parseInt(s,16);
int j = Integer.parseInt(a,16);
SUM = encodeHEX(i+j);
}
若字长大于4位,则进行切片操取出最高位和后四位,然后换成10进制后相加并换成16进制。
2.3.5 对进位后的和用ffff减去,所得的差即取反。
下面展示一些 内联代码片
。
//对16进制取反
public String qufan(String a) {
String m;
int i,j = 0xffff;
i = Integer.parseInt(a,16);
m = encodeHEX(j-i);
return m;
}
如图,是进行取反的函数,将字符串a转换成10进制的整数后,用0xffff的10进制整数减去,再转换成16进制,即可得到去饭后的结果。此时整个运行结果结束。
三,程序运行界面与结果
3.1运行初始界面
如图,因为一个IP地址不合法(>255),检测出后进行提示,提示重新输入。
如上图,因为IP地址不合法(输入中有字母),检测出后进行提示,提示重新输入。
接下来我会简单介绍下判断是否合法是如何实现的。
//判断输入的IP是否全为10进制
public boolean judge_ip(String a) {
boolean b = null != null;
for(int i=0 ; i<a.length() ; i++){
if(Character.isLetter(a.charAt(i))) b = true;//用char包装类中的判断字母的方法判断每一个字符
else b = false;
}
return b;
}
//判断IP是否合法
public boolean Judge(String a) {
int b = Integer.parseInt(a);
if(b>=0&&b<=255) return true;
else return false;
}
如上,是进行检验的两个函数,第一个函数judge_ip()作用是检验IP地址是否均为数字10进制,若检测到字符则返回true;而第二个函数比较简单,是接受字符串的数字,换成整形后判断范围,若在范围内则说明IP正确,返回true,反正不正确。两者均返回布尔值,通过布尔值判断。
boolean judge1 = judge_ip(S_IP_add1.getText())||judge_ip(S_IP_add2.getText())||judge_ip(S_IP_add3.getText())||judge_ip(S_IP_add4.getText()||judge_ip(T_IP_add1.getText())||judge_ip(T_IP_add2.getText())||judge_ip(T_IP_add3.getText())||judge_ip(T_IP_add4.getText());
if(judge1 == true) JOptionPane.showMessageDialog(null, "地址输入不合法!请重新输入");
如上,是进行是否均为10进制的判断。通过“或运算”,检查是否用10进制输入。因为judge_ip()函数是有字符就返回true,因此只需有一个true,则抛出提示,提示输入错误。
boolean judge = Judge(S_IP_add1.getText())&&Judge(S_IP_add2.getText())&&Judge(S_IP_add3.getText())