《计算机网络》第十章.docx

上传人:b****7 文档编号:23985105 上传时间:2023-05-23 格式:DOCX 页数:20 大小:134.38KB
下载 相关 举报
《计算机网络》第十章.docx_第1页
第1页 / 共20页
《计算机网络》第十章.docx_第2页
第2页 / 共20页
《计算机网络》第十章.docx_第3页
第3页 / 共20页
《计算机网络》第十章.docx_第4页
第4页 / 共20页
《计算机网络》第十章.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

《计算机网络》第十章.docx

《《计算机网络》第十章.docx》由会员分享,可在线阅读,更多相关《《计算机网络》第十章.docx(20页珍藏版)》请在冰豆网上搜索。

《计算机网络》第十章.docx

《计算机网络》第十章

计算机网络课程设计报告

题目:

发现网络中的活动主机

******

学号:

************

专业班级:

计算机科学与技术12101班

同组姓名:

 

*******

设计时间:

2015年上学期第17周

指导老师意见:

 

评定成绩:

签名:

日期:

2015年7月3日

一、程设计的目的和意义

IP协议的优点是简洁,但缺少差错控制和查询机制,而网际控制报文协议(ICMP)具有补充IP功能的作用。

在网络管理中,常常要确定当前网络中处于活动状态的主机,这时可以通过使用ICMP的回送和回送响应消息来完成这项工作。

本课程设计的目的就是编制程序,利用ICMP数据包,发现指定网段中的活动主机。

通过课程设计,使学生更加熟悉ICMP报文的结构,对ICMP协议有更好的理解和认识。

二、程设计的内容和要求

设计程序,其功能是发送ICMP数据包,以获取指定网段中的活动主机,并将结果显示在标准输出上。

程序的具体要求如下:

1)用命令行形式运行:

scanhostStart_adressEnd_adress

其中scanhost为程序名;Start_adress为被搜索网段的开始IP地址;End_adress

为被搜索网段的结束IP地址。

2)输出格式为:

活动主机1

活动主机2

……

三、课程设计的相关技术

编制程序前首先要对ICMP报文的格式有一定的了解,ICMP报文是在IP数据报内部传输的,其结构如图1所示。

图1ICMP封装在IP内部

ICMP报文的格式如图2所示。

所有报文的前4个字节都是一样的,但是其它字节则互不相同。

其中类型字段可以有15个不同的值,以描述特定类型的ICMP报文,某些ICMP报文还使用代码字段的值来进一步描述不用的条件。

按验和字段为2字节,校验的范围是整个ICMP报文。

检验和是必须的,其计算方法与IP协议头部校验和的计算方法一样。

078151631(位)

类型字段

代码字段

校验和字段

(不同类型和代码有不同内容)

图2ICMP报文

各种类型的ICMP报文如图3所示(ICMP报文类型),不同类型由报文中的类型字段和代码字段来共同决定。

本课程设计的目的是发现网络中的活动主机,就是使用ICMP的回送和回送响应消息发现网络中的活动主机,即Ping消息的请求和应答。

那幺,发送的ICMP的数据包类型设置为回送请求(类型号为8)。

四、课程设计过程

本程序使用原始套接字生成ICMP报文来进行活动主机的探查。

这个程序使用的是回送请求与应答消息。

程序的大致思想是把ICMP的数据包类型设置为回送请求,将它发送给网络上的一个IP地址,如果这个IP地址已经被占用的话,那幺使用位于这个IP地址的主机

上的TCP/IP软件就能够接收到这个ICMP回送请求,从而返回一个ICMP回送响应(类型号为0)信息。

信息封装在一个IP包中,我们需要解析该IP包,从中找到ICMP数据信息。

相反,如果这个IP地址没有人使用,那幺发送的ICMP回送请求在设定的延时内就不可能得到响应。

在初始化原始套接字之后,本程序就要开始在一个IP网段内寻找活动主机。

因为要寻找的主机可能很多,为节省时间可以采用多线程编程。

下面接结合核心代码对程序的具体实现进行讲解,同时为使程序流程更加清晰,去掉了错误检查等保护性代码。

4.1、使用原始套接字

为了实现发送/监听ICMP报文,必须使用原始套接字,创建原始套接字的代码如下:

socketsockRaw;

sockRaw=SAocket(AF_INET,sock_Raw,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);

在WSASocket函数中,我们使用IPPROTO_ICMP表示接收ICMP数据包,为了使用发送超时设置(设置SO_RCVTIMEO或SO_SNDTIMEO),必须将标志位置为WSA_FLAG_OVERLAPPED。

然后调用setsockopt函数设置读取延迟。

Inttimeout=1000;

setsockopt(sockRaw,SQL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout);

setsockopt(sockRaw,SQL_socket,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout);

 

类型代码描述

00回送响应(PING应答)

3目的不可达

1网络不可达

2主机不可达

3协议不可达

4端口不可达

5需要进行分片但设置了禁止分片比特

6源主机选择路由失败

7无法识别目的网络

8无法识别目的主机

9源主机被隔离

10目的网络被禁止

11目的主机被禁止

12由于服务类型(TOS),网络不可达

13由于服务类型(TOS),主机不可达

14由于过滤,通信被强行禁止

15主机越权

16优先权终止生效

40源端被关闭(基本流控制)

5重定向

1对网络重定向

2对主机重定向

3对服务类型和网络重定向

4对服务类型和主机重定向

80回送请求(PING请求)

90路由器通告

100路由器请求

11超时

1传输期间生存期减为0

2数据报组装期间生存期减为0

12参数问题

1各种IP头部错误

2缺少必须的选项

130时间戳请求

140时间戳应答

150信息请求(已作废)

160信息应答(已作废)

170地址掩码请求

180地址掩码应答

图3ICMP报文类型

在setsockopt函数中,sockRaw是之前创建的原始套接字,设置SQL_SOCKET表明使用基本套接字处理ICMP报文。

设置SO_RCVTIMEO表示使用接收超时设置,SO_SNDTIMEO表示使用发送超时设置,在这里,超时时间均设置为1000ms。

4.2、定义IP头部和ICMP头部的数据结构

由于socket发送/捕获的是IP包,因此要分别定义IP头部的数据结构ICMP头部数据结构。

4.3、填充并发送回送请求类型的ICMP报文

为了使收到数据包的目的主机发送响应,我们需要向目的主机发送回送请求类型的ICMP报文。

从图3中可知,回送请求的类型号为8。

因此ICMP报文的填充代码如下:

checksum为校验和的函数,设校验和初值为0,然后对数据每16为求异或,结果取反,便得校验和。

其代码如下:

USHORTchecksum(USHORT*buffer,intsize){

unsignedlongcksum=0;

while(size>1){

cksum+=*buffer++;

size-=sizeof(USHORT);}

if(size){cksum+=*(UCHAR*)buffer;}

cksum=(cksum>>16)+(cksum&0xffff);

cksum+=(cksum>>16);

return(USHORT)(-cksum);}

填充ICMP报文之后,应在ICMP报文之前加上IP报头并发送出去。

可调用下面的代码发送数据包。

注意,这里的DEST是填入目的主机IP地址的一个sockaddr_in数据结构,IP—STRING是目的主机的IP地址字符串。

structsockaddr_indest;

dest.sin_family=AF_INET;

dest.sin_addr.s_addr=inet_addr(IP_STRING);//填入搜索的IP地址

sendto(sockRaw,icmp_data,datasize,0,(sockaddr*)&dest,sizeof(dest));

4.4、解析数据包

如果所Ping的目的主机所在,那么它会发送一个回送应答包。

这是一个IP包,收到后解析此数据包并获取其中的ICMP信息。

根据IP报头信息中的IP报头长度字段,就可以得到ICMP报文的真实地址。

ICMP数据包中的IP地址就是活动主机的IP。

代码如下:

4.5、程序流程图

一个用多线程实现的程序在课程设计过程的第三部分中给出,以下分别是主程序流程图和子程序流程图:

 

N

YY

N

Y

N

 

图4主程序流程图

 

 

Y

N

Y

N

Y

N

 

图5子程序流程图

 

五、程序运行结果

六、课程设计小结

通过此次课程设计,我加深了对ICMP协议的理解,巩固了课堂知识。

由于网络协议比较抽象、难学,自己学得也不够深入,加上还要把所学知识运用到实践中来,所以一开始时感觉比较困难,而且在调试过程中难免要出现一些如变量没有定义、缺少头文件、大小写错误以及其它问题,通过查阅文献资料、向同学请教以及认真地思考与分析,逐一对错误进行了调试,才使得程序能正常运行,大体上符合了设计的目的和要求。

在程序的调试过程中,出现问题是正常的,关键是如何去发现问题的根源,然后去解决它。

为了能够快速地确定错误的原因,尽快的排除程序错误,通常把程序错误划分为三种类型:

语法错误、运行错误和逻辑错误。

在设计过程中,我们可以先找出问题,看是属于哪一类错误,然后再将问题一一解决,这样既解决了疑难问题又节省了不少时间。

 

参考文献

[1]吴功宜,胡晓英,张仁,何云,王宁编著.《计算机网络课程设计》[M].北京:

机械工业出版社,2014.8

[2]谢希仁著.《计算机网络(第六版)》.北京.电子工业出版社,2013.6

[3]陈坚,陈伟.《VisualC++网络高级编程》[M].北京:

人民邮电出版社,2012.6

[4]陈鸣等.《计算机网络实验教程,从原理到实践》.北京:

机械工业出版社,2007

[5]吴功宜,等.《计算机网络高级教程》[M].北京:

清华大学出版社,2007.6

[6]吴功宜,等.《计算机网络高级软件编程技术》[M].北京:

清华大学出版社,2008.6

[7]吴功宜,等.《网络安全高级软件编程技术》[M].北京:

清华大学出版社,20010.6

附录:

源代码

#include

#include

#include

#pragmacomment(lib,"Ws2_32.lib")

//IP包头部结构

typedefstructiphdr

{

unsignedintheadlen:

4;//头部长度

unsignedintversion:

4;//版本号

unsignedchartos;//服务类型

unsignedshorttotallen;//总长度

unsignedshortid;//IP包ID号

unsignedshortfalg;//标记

unsignedcharttl;//生存时间

unsignedcharprot;//协议类型

unsignedshortchecksum;//校验和

unsignedintsourceIP;//源IP地址

unsignedintdestIP;//目的IP地址

}IpHeader;

//ICMP包头布结构

typedefstructicmphdr

{

BYTEtype;

BYTEcode;

USHORTchecksum;

USHORTid;

USHORTseg;

}IcmpHeader;

#defineICMP_RCHO8

#defineICMP_RCHO_REPLY0

#defineICMP_MIN8

#defineSTATUS_FAILED0xFFFF

#defineDEF_PACKET_SIZE32

#defineMAX_PACKET1024

#defineMAX_PING_PACKET_SIZE(MAX_PACKET+sizeof(IpHeader))

voidfill_icmp_data(char*,int);

USHORTchecksum(USHORT*,int);

voiddecode_resp(char*,int,structsockaddr_in*);

DWORDWINAPIFindIP(LPVOIDpIPAddrTemp);

WSADATAwsaData;

SOCKETsockRaw;//原始套接字

structsockaddr_indest,from,end;

intfromlen=sizeof(from);//接收ICMP包长度

char*recvbuf=newchar[MAX_PING_PACKET_SIZE];

unsignedintaddr=0;

longThreadNumCounter=0,ThreadNumLimit=20;

long*aa=&ThreadNumCounter;

 

//填充ICMP包的函数

voidfill_icmp_data(char*icmp_data,intdatasize)

{

IcmpHeader*icmp_hdr;

char*datapart;

icmp_hdr=(IcmpHeader*)icmp_data;

icmp_hdr->type=ICMP_RCHO;//设置类型信息

icmp_hdr->id=(USHORT)GetCurrentThreadId();//设置当前线程ID

datapart=icmp_data+sizeof(IcmpHeader);//计算ICMP包数据部分

memset(datapart,'A',datasize-sizeof(IcmpHeader));

}

//解析IP地址的函数

voiddecode_resp(char*buf,intbytes,structsockaddr_in*from)

{

IpHeader*iphdr;

IcmpHeader*icmphdr;

unsignedshortiphdrlen;

iphdr=(IpHeader*)buf;

//跳过IP包头部

iphdrlen=iphdr->headlen*4;

icmphdr=(IcmpHeader*)(buf+iphdrlen);

//数据包太短,跳过

if(bytes

return;

//不是回送响应,丢弃

if(icmphdr->type!

=ICMP_RCHO_REPLY)

return;

//ID不符

if(icmphdr->id!

=(USHORT)GetCurrentThreadId())

return;

cout<<"活动主机:

"<sin_addr)<

}

//校验和计算函数

USHORTchecksum(USHORT*buffer,intsize)

{

unsignedlongcksum=0;

while(size>1)

{

cksum+=*buffer++;

size-=sizeof(USHORT);

}

if(size)

{

cksum+=*(UCHAR*)buffer;

}

cksum=(cksum>>16)+(cksum&0xffff);

cksum+=(cksum>>16);

return(USHORT)(~cksum);

}

//线程调用函数

DWORDWINAPIFindIP(LPVOIDpIPAddrTemp)

{

InterlockedIncrement(aa);

charicmp_data[MAX_PACKET];

memset(icmp_data,0,MAX_PACKET);

intdatasize=DEF_PACKET_SIZE;

datasize+=sizeof(IcmpHeader);

//填充ICMP包

fill_icmp_data(icmp_data,datasize);

((IcmpHeader*)icmp_data)->checksum=0;

((IcmpHeader*)icmp_data)->seg=0;

//计算校验和后填入

((IcmpHeader*)icmp_data)->checksum=checksum((USHORT*)icmp_data,datasize);

//发送ICMP包

intbwrote=sendto(sockRaw,icmp_data,datasize,0,(structsockaddr*)pIPAddrTemp,sizeof(dest));

intn=0;

if(bwrote==SOCKET_ERROR)

{

if(WSAGetLastError()==WSAETIMEDOUT)

{

cout<<"timedout"<

}

cout<<"sendtofailies"<

ExitProcess(STATUS_FAILED);

n=1;

}

if(WSAGetLastError()==WSAETIMEDOUT)

{

cout<<"timedout"<

ExitProcess(STATUS_FAILED);

n=1;

}

if(bwrote

{

cout<<"Worte"<

ExitProcess(STATUS_FAILED);

n=1;

}

intbread=recvfrom(sockRaw,recvbuf,MAX_PING_PACKET_SIZE,0,(structsockaddr*)&from,&fromlen);

if(bread==SOCKET_ERROR)

{

if(WSAGetLastError()==WSAETIMEDOUT)

cout<<"timedout"<

cout<<"recvfromfalied"<

ExitProcess(STATUS_FAILED);

n=1;

}

if(n==0)

{

decode_resp(recvbuf,bread,&from);

InterlockedDecrement(aa);

}

return0;

}

voidmain(intargc,char*argv[])

{

//检查输入命令格式

if(argc!

=3)

{

cout<<"输入格式错误:

996start_adressend_adress"<

return;

}

//开始使用Ws2_32.dll

if(WSAStartup(MAKEWORD(2,1),&wsaData)!

=0)

{

cout<<"WASStartupfailed"<

ExitProcess(STATUS_FAILED);

}

//创建原始套接字

sockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);

if(sockRaw==INVALID_SOCKET)

{

cout<<"WASSocketet()falied"<

ExitProcess(STATUS_FAILED);

}

//设置接收延时

inttimeout=1000;

intbread=setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));

if(bread==SOCKET_ERROR)

{

cout<<"FAILEDTOSEYRECVTIMEOUT"<

ExitProcess(STATUS_FAILED);

}

//设置发送延时

timeout=1000;

bread=setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));

if(bread==SOCKET_ERROR)

{

cout<<"FAILEDTOSEYRECVTIMEOUT"<

ExitProcess(STATUS_FAILED);

}

//初始化地址结构

memset(&dest,0,sizeof(dest));

unsignedlongstartIP,endIP;

dest.sin_family=AF_INET;

dest.sin_addr.s_addr=inet_addr(argv[1]);

startIP=inet_addr(argv[1]);

end.sin_family=AF_INET;

end.sin_addr.s_addr=inet_addr(argv[2]);

endIP=inet_addr(argv[2]);

HANDLEhThread;

while(htonl(startIP)<=htonl(endIP))

{

//判断线程数

if(ThreadNumCounter>ThreadNumLimit)

{

Sleep(5000);

continue;

}

DWORDThreadID;

sockaddr_in*pIPAddrTemp=new(sockaddr_in);

if(!

pIPAddrTemp)

{

cout<<"memoryallocfailed"<

return;

}

*pIPAddrTemp=dest;

//创建新线程

clock_tstart;

start=clock();

hThread=CreateThread(NULL,NULL,FindIP,(LPVOID)pIPAddrTemp,NULL,&ThreadID);

longi=60000000L;

while(

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1