李杰15898508396QQ:459123240用TCP/IP进行网际互联习题解答4.2为不使用ARP的网络接口构思一份地址绑定软件设计草图解答:通过直接映射进行转换,考虑proNET令牌环网络,它使用小整数表示物理地址,并且允许用户在把接口板安装到计算机中时自己选择硬件地址,对于这种网络硬件,使其地址转换易于进行的关键是,只要它的IP地址和物理地址可以自由选择,那么总可以让它们中的某些部分是相同的,一般的,分配IP地址的主机号部分为1,2,3等,然后在安装网络接口硬件时,选择与IP地址对应的物理地址。例如,系统管理员为IP地址为192.5.48.3的计算机选择物理地3,因为192.5.48.3是个主机部分等于3的C类地址。对于类似proNET的网络,从IP地址计算出物理地址是很容易的,这种计算是从ID地址中取其主机部分,因为只需要几条机器指令,所以计算效率很高。由于映射可以在不引用外部数据的情况下完成,所以很易于维护。最后,不需要改变现在的分配或重新编译代码就可以在网络中添加新机器。从概念上讲,选择一个使地址转换高效的编号方法就是选择一个函数f,f把IP地址映射到物理地址。设计人员也可以根据硬件选择一种物理地址编号方法。IP地址IA意味着计算PA=f(IA)我们要f的计算高效,如果物理地址的集合受到限制,也有可以实现其他高效的映射,例如,在诸如ATM的面向连接的网络上IP,就无法随意选择物理地址。在这种网络中,由一台或多台计算机(服务器)存储地址对,每个地址对中一个Internet地址和对应的物理地址。一般情况下,这样的服务器把地址对存储在主存中的一张表里,以加快搜索速度。在这种情况下,为了迅速转换地址,软件可以用传统的哈希函数搜索地址表。4.4设想某网点决定对仅在给定的网络中惟一的地址ARP(不用ARP也可能实现地址绑定)。我们的范例程序能在与两个这种网络相连接的一个网关上正确地运行吗?为什么?解答:不可以。“仅在给定的网络中惟一的地址”意味着不同的网络地址不一定唯一(可以详细分析)。4.8因为任何设备都有可能响应一个ARP分组的广播,所以ARP容易上当受骗。通过增加判断以下的语句来修改范例:(a)两个或更多个设备响应了某个给定IP地址的请求分组。(b)一个设备接收到自己的IP地址的ARP绑定。(c)一个设备响应了多个IP地址请求分组。解答提示:在arp_in函数中的修改方法:(a)有很多种方法,比如:分析判断多个设备的确认分组的mark,从中选出正确的,比较复杂点;或者进行屏蔽;….(b)直接屏蔽(c)直接屏蔽5.1“0”的反码有两个值,cksum将返回哪一个?解答:注意cksum函数的返回值为short类型,sum为unsignedlong型,0的反码为32个1,强制转换为short类型后为16个1。5.3考虑为所有发往IP的数据报使用一个单一的输入队列的实现方案。这种方案的主要缺点是什么?解答:1.一个网络接口由于大量数据造成的溢出将会影响所有其他接口。2.对伪网络接口的判断比较麻烦。3.优先级处理上比较死板,只能是先到先得。5.6指出为什么在没有数据报等待被处理的情况下,ipproc也有可能做最后一次循环,提示:考虑IP进程和一个放置数据并向IP发送报文的驱动程序之间的定时处理。解答:当ipgetp选择了一个数据报之后进行发送,若对方未成功接收而等待时间已超,则ipproc会再做一次循环。6.2散列表元的数目决定了桶散列方案的有效性,因为它决定了的平均长度。如果希望平均每个不多于3个表项,那么要保存1000条需要多大的内存?解答:由题意算出散列表元的数目为1000/3≈334个每个表元大小为4B,每个表项的大小为32B所以需要的内存大小为32B*1000+4B*334=33336B6.3如果过程rtdel调用rtfree而不是使用宏RTFREE,结果怎样?解答:由rtfree函数定义:intrtfree(structroute*prt){if(!Route.ri_valid)returnSYSERR;wait(Route.ri_mutex);RTFREE(prt);signal(Route.ri_mutex);returnOK;}当rtdel调用rtfree函数后,可能会出现如下的死锁情况:wait(Route.ri_mutex)wait(Route.ri_mutex)Signal(Route.ri_mutex)Signal(Route.ri_mutex)7.2仔细查看ipputp和ipfhcopy过程。会不会出现ipputp将分片的最大有效长度估计得过小的情况?为什么?1.解答:2.Intipputp(unsignedifn,IPaddrnh,structep*pep)3.{4.structnetif*pni=&nif[ifn];5.structip*pip;6.inthlen,maxdlen,tosend,offset,offindg;7.if(pni-ni_state==NIS_DOWN){//判断接口是否启用8.freebuf(pep);9.returnSYSERR;10.}11.pip=(structip*)pep-ep_data;//复制数据部分12.if(pip-ip_len=pni-ni_mtu){//若数据报长度小于最大传输单元,则不用分片13.pep-ep_nexthop=nh;14.pip-ip_cksum=0;15.iph2net(pip);16.pep-ep_order&=~EPO_IP;17.pip-ip_cksum=cksum((WORD*)pip,IP_HLEN(pip));18.returnnetwrite(pni,pep,EP_HLEN+net2hs(pip-ip_len));19.}1./*else,weneedtofragmentit*/2.if(pip-ip_fragoff&IP_DF){//确定是否能够分片3.IpFragFails++;4.icmp(ICT_DESTUR,ICC_FNADF,pip-ip_src,pep,0);5.returnOK;6.}7.maxdlen=(pni-ni_mtu-IP_HLEN(pip))&~7;//确定可发送的最大数据量pni-ni_mtu8.offset=0;//上面的pni是网络接口单元最大传输量9.offindg=(pip-ip_fragoff&IP_FRAGOFF)3;//偏移量,但这里左移3保存了分片控制的那3位10.tosend=pip-ip_len-IP_HLEN(pip);//要发送数据的长度,注意这里是pip-len。11.12.while(tosendmaxdlen){13.if(ipfsend(pni,nh,pep,offset,maxdlen,offindg)!=OK){//如果发送失败,丢弃14.IpOutDiscards++;15.freebuf(pep);16.returnSYSERR;17.}18.IpFragCreates++;//否则,分片数+119.tosend-=maxdlen;//将发送数据的长度减去最大可发送数据量,表示已经发送一个分片。1.//新偏移量置为最大可发送数据量+当前偏移量,表示下一个分片的数据从这里开始2.offset+=maxdlen;3.offindg+=maxdlen;4.}5.//接下来的代码,处理最后一个分片6.IpFragOKs++;7.IpFragCreates++;8.hlen=ipfhcopy(pep,pep,offindg);//由于是最后一个分片,直接用offindg复制到原来9.pip=(structip*)pep-ep_data;10./*slidetheresidualdown*/11.memcpy(&pep-ep_data[hlen],&pep-ep_data[IP_HLEN(pip)+offset],tosend);12./*keepMF,ifthiswasafragtostartwith*/13.pip-ip_fragoff=(pip-ip_fragoff&IP_MF)|(offindg3);14.pip-ip_len=tosend+hlen;15.pip-ip_cksum=0;16.iph2net(pip);17.pep-ep_order&=~EPO_IP;18.pip-ip_cksum=cksum((WORD*)pip,hlen);19.pep-ep_nexthop=nh;20.returnnetwrite(pni,pep,EP_HLEN+net2hs(pip-ip_len));21.}1.然后是发送一个数据报片函数:2.Intipfsend(structnetif*pni,IPaddrnexthop,structep*pep,3.unsignedoffset,unsignedmaxdlen,unsignedoffindg)4.{5.structep*pepnew;6.structip*pip,*pipnew;7.inthlen,len;8.pepnew=(structep*)getbuf(Net.netpool);//分配新缓冲区9.if(pepnew==(structep*)SYSERR)10.returnSYSERR;11.pepnew-ep_order=~0;12.hlen=ipfhcopy(pepnew,pep,offindg);/*copytheheaders*/13.pip=(structip*)pep-ep_data//复制数据;14.pipnew=(structip*)pepnew-ep_data;//分配数据格式15.pipnew-ip_fragoff=IP_MF|(offindg3);16.pipnew-ip_len=len=maxdlen+hlen;//确定首部长17.pipnew-ip_cksum=0;18.iph2net(pipnew);19.pepnew-ep_order&=~EPO_IP;20.pipnew-ip_cksum=cksum((WORD*)pipnew,hlen);21.22.memcpy(&pepnew-ep_data[hlen],&pep-ep_data[IP_HLEN(pip)+offset],maxdlen);//复制数据23.pepnew-ep_nexthop=nexthop;24.returnnetwrite(pni,pepnew,EP_HLEN+len);25.}26.该函数其实和iputp类似。不多说了27.然后是复制数据报首部函数1.Intipfhcopy(structep*pepto,structep*pepfrom,unsignedoffindg)2.{3.structip*pipfrom=(structip*)pepfrom-ep_data;4.unsignedi,maxhlen,olen,otype;5.unsignedhlen=(IP_MINHLEN2);//最小IP数据报头部长度,转换成字节6.if(offindg==0){//第一个IP分片,所有的数据报头都拷贝过来,包括选项部分7.memcpy(pepto,pepfrom,EP_HLEN+IP_HLEN(pipfrom));8.returnIP_HLEN(pipfrom);9.}/*以下说明不是第一个IP分片*/10.memcpy(pepto,pepfrom,EP_HLEN+hlen);//先拷贝除IP选项外的报头,注意有EP_HLEN11./*copyoptions*/12./*拷贝选项部分*/13.maxhlen=IP_HLEN(pipfrom);//现在的报头,比如有IP选项了14.i=hlen;//最小报头,没有IP选项15.while(imaxhlen){//说明有IP选项16.otyp