[课件资料]ip首部校验和算法
实验
报告
软件系统测试报告下载sgs报告如何下载关于路面塌陷情况报告535n,sgs报告怎么下载竣工报告下载
(3)
——首部检验和的编程实现 一、 实验人员
二、实验内容和要求
(一)实验内容
编写一个计算IP报文中首部校验和的程序,并且通过抓包随机选择一个数据报,提取出IP报文首部部分,根据程序计算出校验和的计算值,与报文中检验和对比,检验程序的正确性,计算结果为0保留数据报,否则丢弃。
(二)实验要求
1.掌握IP数据报的结构,通过wireshark抓包随机选择一个TCP数据报,提取IP报部分,并找到首部。
2.学习理解并运用IP首部校验和的计算算法,通过程序实现。
三、实验环境
Wireshark抓包工具
Microsoft visual studio 2010 C#
四、实验过程与结果分析
(一)实验过程
1.利用wireshark抓包分析包格式并提取IP首部 (1)IP数据报格式
如图1,IP数据报的首部为前20字节。因为首部校验和的计算只需要IP数据报的首部20个字节即可,数据部分不参加运算。所以只需要把IP数据包中的前20个16进制数提取出来作为运算的数据即可。
图 1 IP数据包格式
(2)抓包得到的数据报
图 2 TCP数据报
如图2,通过wireshark抓包,随机选择一个TCP数据报,根据TCP数据报的格式,我们分析数据报内容可以知道:首先开始6个字节为目的mac地址,后面6个字节为目的mac地址,后面2个字节为
协议
离婚协议模板下载合伙人协议 下载渠道分销协议免费下载敬业协议下载授课协议下载
类型为0800,是IP协议包。所以再后面的20个字节就是IP数据报的首部部分。也就是实验所需要的数据。
IP首部为:450000280000400034060ab73baf84710a687191 并且,通过包的计算的校验和结果,此包被留下,校验和的值为0。也是座位后面对
设计
领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计
程序计算得到结果的一个验证。
2.设计计算首部校验和的的算法
(1)程序设计的函数模块关系
输入IP首部 string IP0
转化为二进制字符串并划分为10个字
段IP1~IP10,函数Getziduan()
求字段反码,函数FanMa()
反码求和函数FanSum();FanSum0();
求出由上一布得到的结果的反码,输出
结果
(2)算法流程
首先将IP首部即40位16进制的字符串转化为二进制字符串,然后以每16位为一个字段,分为10个二进制字段。存放在IP1~IP10字符串中;
然后求出每个字段的反码,根据IP数据报格式,可以知道IP6存放的就是校验和,将校验和IP6置位全0;
利用求反码和方法FanMa(),求出10个字段反码相加后的值string sum,然后对字符串sum取反,得到发送时所用的校验码。 假设接收端的IP首部与发送的是相同的,那么其10个字段的利用反码和算法求出的值应为0。
算法的流程与在发送端求出发送的校验码过程相同。
(3)几个主要的方法 将16进制转化为二进制的字符串操作: public static string Change(char a)
{
switch (a)
{
case '0': return "0000";
case '1': return "0001";
case '2': return "0010";
case '3': return "0011";
case '4': return "0100";
case '5': return "0101";
case '6': return "0110";
case '7': return "0111";
case '8': return "1000";
case '9': return "1001";
case 'a': return "1010";
case 'b': return "1011";
case 'c': return "1100";
case 'd': return "1101";
case 'e': return "1110";
case 'f': return "1111";
default: break;
}
return "xxxx";
}
求各字段的反码:
public static string FanMa(string zd)
{
string buff0 = "";
char a;
for (int i = 0; i < zd.Length; i++)
{
a = zd[i];
if (a == '0')
{
buff0 = buff0 + "1";
}
else
{
buff0 = buff0 + "0";
}
}
return buff0;
}
求各字段的和:
public static string FanSum(string ip1, string ip2, string ip3, string ip4, string ip5,
string ip6, string ip7, string ip8, string ip9, string ip10,int len)
{
string buff = "";
buff = FanSum0(ip1, ip2, len);
buff = FanSum0(buff, ip3, len);
buff = FanSum0(buff, ip4, len);
buff = FanSum0(buff, ip5, len);
buff = FanSum0(buff, ip6, len);
buff = FanSum0(buff, ip7, len);
buff = FanSum0(buff, ip8, len);
buff = FanSum0(buff, ip9, len);
buff = FanSum0(buff, ip10, len);
return buff;
}
public static string FanSum0(string ip1, string ip2,int len)
{
string sum = "";
char a;
char b;
string buff="";
string buff1="";
int k = 0;
for (int i = len-1; i >=0; i--)
{
a = ip1[i];
b = ip2[i];
if (a == '0' && b == '1' && k == 0)
{
buff = buff + "1";
k = 0;
continue;
}
if (a == '1' && b == '0' && k == 0)
{
buff = buff + "1";
k = 0;
continue;
}
if (a == '1' && b == '1' && k == 0)
{
buff = buff + "0";
k = 1;
continue;
}
if (a == '1' && b == '1' && k == 1)
{
buff = buff + "1";
k = 1;
continue;
}
if (a == '1' && b == '0' && k == 1)
{
buff = buff + "0";
k = 1;
continue;
}
if (a == '0' && b == '1' && k == 1)
{
buff = buff + "0";
k = 1;
continue;
}
if (a == '0' && b == '0' && k == 1)
{
buff = buff + "1";
k = 0;
continue;
}
if (a == '0' && b == '0' && k == 0)
{
buff = buff + "0";
k = 0;
continue;
}
}
for (int j = len-1; j >= 0; j--)
{
buff1 = buff1 + buff[j];
}
if (k == 1)
sum = FanSum0(buff1, "0000000000000001", 16);
else sum = buff1;
return sum;
}
3.显示结果并与已知值对比
结果显示最后的校验和为0,这个数据包被留下,与实际情况相同,但此时还不能说明算法一定正确,因为我们还没有考虑数据包被丢弃的情况。
在数据包被丢弃的情况下,肯定是最终算的校验和不为0,也就是接受到的IP首部与发送的不同,因此我们只要将接收端用来计算校验和的字段IP1~IP10任意更改一位,使其与原来不同即可。我所做的更改为由原来IP1的反码:1011101011111111,在计算接收端的校验和时更改为:1011101011111110。
所得到的结果为:
所以算法是正确的。
(二)结果分析
通过数据包正确接收和被丢弃两种情况对设计的校验和计算算法的比较,计算的结果与实际情况校验和的值是一致的,因此在数据报在实际通信时,利用校验和的方式可以判定所接收的数据报是否发生了变化,保证了可靠性。同时校验和的方法又是比较简便快速的,减少了时间上的开销,因此是在实际情况下比较适用的方法。
五、小结
(一)实验中曾经出现的犯过的错误、遇到的问题及相应的解决
方案
气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载
。
1.在利用字符串计算字段相加求值时开始没有考虑到计算结果正好是实际值的倒叙,通过调试观察局部变量的方法发现了错误,将计算结果作了顺序的转换,使下面的计算得以正确。
(二)通过本次实验,你的感受是什么,有什么收获。 通过这次实验我的感受是在实现算法时,首先要整理好清楚的思路,将设计的算法用流程图或者草图方式画出实现的步骤,这样能够更加有效率的进行编码,同时还能够使编码更加简洁清楚。同时我还对通过首部校验和来保证数据的可靠性的方法感到十分敬佩,利用很方便简单的方法就完成了校验。最后通过这次实验,我也学习到了校验和算法的设计思想并亲手实现了,锻炼了自己的动手能力,也进一步对网络通信培养了兴趣。
六、附录
[1] 程序全部代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 校?ê验??和?ª
{
class Program
{
static void Main(string[] args)
{
string IP0 = "450000280000400034060ab73baf84710a687191";
string sum = ""; //存ä?放??发??é送?ª端?的Ì?反??ä码?和?ª
string sum1 = ""; //存ä?放??接??收º?端?的Ì?反??ä码?和?ª
string IP1 = ""; //第Ì??一??个?16位?字Á?段?
string IP2 = ""; //第Ì??二t个?
; //第Ì??三?y个? string IP3 = ""
string IP4 = ""; //第Ì??四?个?
string IP5= ""; //第Ì??五?个?
string IP6 = ""; //首º?Á部?校?ê验??和?ª
string IP7 = ""; //第Ì??七?个?
string IP8 = ""; //第Ì??八ã?个?
string IP9 = ""; //第Ì??九?个?
string IP10 = ""; //第Ì??十º?个?
IP1 = Getziduan(IP0, 0);
IP2 = Getziduan(IP0, 4);
IP3 = Getziduan(IP0, 8);
IP4 = Getziduan(IP0, 12);
IP5 = Getziduan(IP0, 16);
IP6 = Getziduan(IP0, 20);
IP7 = Getziduan(IP0, 24);
IP8 = Getziduan(IP0, 28);
IP9 = Getziduan(IP0, 32);
IP10 = Getziduan(IP0, 36);
Console.WriteLine("IP1::::" + IP1);
Console.WriteLine("IP2::::" + IP2);
Console.WriteLine("IP3::::" + IP3);
Console.WriteLine("IP4::::" + IP4);
Console.WriteLine("IP5::::" + IP5);
Console.WriteLine("IP6::::" + IP6);
Console.WriteLine("IP7::::" + IP7);
Console.WriteLine("IP8::::" + IP8);
Console.WriteLine("IP9::::" + IP9);
Console.WriteLine("IP10:::" + IP10);
Console.WriteLine("首º?Á部?校?ê验??和?ª为aIP6:êo:êo" + IP6);
Console.WriteLine("*******************************************");
Console.WriteLine("计?算?接??收º?端?的Ì?反??ä码?和?ª");
IP6 = "0000000000000000";
Console.WriteLine("发??é送?ª端?将?首º?Á部?校?ê验??和?ª字Á?段?置?零??IP6为a:êo:êo" + IP6);
Console.WriteLine("求??反??ä码?的Ì?结??果?:êo");
IP1 = FanMa(IP1);
IP2 = FanMa(IP2);
IP3 = FanMa(IP3);
IP4 = FanMa(IP4);
IP5 = FanMa(IP5);
IP6 = FanMa(IP6);
IP7 = FanMa(IP7);
IP8 = FanMa(IP8);
IP9 = FanMa(IP9);
IP10 = FanMa(IP10);
Console.WriteLine("IP1的Ì?反??ä码?为a:êo:êo:êo" + IP1);
Console.WriteLine("IP2的Ì?反??ä码?为a:êo:êo:êo" + IP2);
Console.WriteLine("IP3的Ì?反??ä码?为a:êo:êo:êo" + IP3);
Console.WriteLine("IP4的Ì?反??ä码?为a:êo:êo:êo" + IP4);
Console.WriteLine("IP5的Ì?反??ä码?为a:êo:êo:êo" + IP5);
Console.WriteLine("IP6的Ì?反??ä码?为a:êo:êo:êo" + IP6);
Console.WriteLine("IP7的Ì?反??ä码?为a:êo:êo:êo" + IP7);
Console.WriteLine("IP8的Ì?反??ä码?为a:êo:êo:êo" + IP8);
Console.WriteLine("IP9的Ì?反??ä码?为a:êo:êo:êo" + IP9);
Console.WriteLine("IP10的Ì?反??ä码?为a:êo:êo:êo" + IP10);
sum = FanSum(IP1, IP2, IP3, IP4, IP5, IP6, IP7, IP8, IP9, IP10, 16);
Console.WriteLine("反??ä码?和?ª的Ì?计?算?结??果?为a:êo:" + sum);
Console.WriteLine("***************************************");
sum = FanMa(sum);
IP6 = sum;
Console.WriteLine("计?算?接??收º?端?的Ì?各?Â字Á?段?的Ì?反??ä码?和?ª:êo");
Console.WriteLine("将?反??ä码?和?ª的Ì?反??ä码?写?ä入??校?ê验??和?ª中D:êo:êo" + IP6);
sum1 = FanSum(IP1, IP2, IP3, IP4, IP5, IP6, IP7, IP8, IP9, IP10, 16);
Console.WriteLine("反??ä码?和?ª就?ª算?结??果?为a:êo:êo" + sum1);
sum1 = FanMa(sum1);
Console.WriteLine("反??ä码?和?ª再??求??反??ä码?即?ä为a接??收º?方??的Ì?检??验??和?ª结??果?为a:êo:êo" + sum1);
Console.Read();
}
a一??个?字Á?段?*/ /*将?每?16位?划?分??为
public static string Getziduan(string ip,int i)
{
char a;
string buff1="";
string buff2="";
for(int j=i;j
=0; i--)
{
a = ip1[i];
b = ip2[i];
if (a == '0' && b == '1' && k == 0)
{
buff = buff + "1";
k = 0;
continue;
}
if (a == '1' && b == '0' && k == 0)
{
buff = buff + "1";
k = 0;
continue;
}
if (a == '1' && b == '1' && k == 0)
{
buff = buff + "0";
k = 1;
continue;
}
if (a == '1' && b == '1' && k == 1)
{
buff = buff + "1";
k = 1;
continue;
}
if (a == '1' && b == '0' && k == 1)
{
buff = buff + "0";
k = 1;
continue;
}
if (a == '0' && b == '1' && k == 1)
{
buff = buff + "0";
k = 1;
continue;
}
if (a == '0' && b == '0' && k == 1)
{
buff = buff + "1";
k = 0;
continue;
}
if (a == '0' && b == '0' && k == 0)
{
buff = buff + "0";
k = 0;
continue;
}
}
for (int j = len-1; j >= 0; j--)
{
buff1 = buff1 + buff[j];
}
if (k == 1)
sum = FanSum0(buff1, "0000000000000001", 16);
else sum = buff1;
return sum;
}
/*16进?制?的Ì?字Á?符??串ä?化??为a二t进?制?字Á?符??串ä?*/
public static string Change(char a)
{
switch (a)
{
case '0': return "0000";
case '1': return "0001";
case '2': return "0010";
case '3': return "0011";
case '4': return "0100";
case '5': return "0101";
case '6': return "0110";
case '7': return "0111";
case '8': return "1000";
case '9': return "1001";
case 'a': return "1010";
case 'b': return "1011";
case 'c': return "1100";
case 'd': return "1101";
case 'e': return "1110";
case 'f': return "1111";
default: break;
}
return "xxxx";
}
}
}