发现网络中的活动主机.docx
《发现网络中的活动主机.docx》由会员分享,可在线阅读,更多相关《发现网络中的活动主机.docx(16页珍藏版)》请在冰豆网上搜索。
发现网络中的活动主机
计算机网络课程设计报告
题 目:
发现网络中的活动主机
专业班级:
计科10102班
姓 名:
林
学 号:
7
同组:
谭莫然、谭斌、绥海
1.设计目标:
现在一个机房的主机已经达到了一定数量,进行网络管理时,常常需要确定当前网络中处理活动状态的主机。
本设计的目标就是编制程序,利用ICMP的回送请求和回送响应,来发现指定网段中的活动主机。
2.设计功能:
用命令行形式运行:
scanhostStart_IPEnd_IP,来发现活动主机并显示。
(注:
scanhost为程序名,Start_IP为被搜索望断的起始IP,End_IP为其终止IP。
)
显示格式形式如下粗体部分:
活动主机:
172.16.201.11
活动主机:
172.16.201.12
活动主机:
172.16.201.13
活动主机:
172.16.201.15
环境要求:
Windows95/98/2000/XP/dos下能运行,使用VC++编写程序
3.设计原理:
本设计的主体思想是使用ICMPECHO数据包来探测指定网段的活动主机。
具体法是:
通过简单的发送一个ICMPECHO(Type8)数据包到目标主机,如果ICMPECHOReply(ICMPtype0)数据包接受到,说明主机是存活状态。
如果没有就可以初步判断主机没有在线或者使用了某些过滤设备过滤了ICMP的REPLY。
ICMP全称InternetControlMessageProtocol,工作在OSI的网络层。
它的中文名为因特网控制报文协议。
ICMP报文要封装在IP数据报部才能传输。
其结构如(图一)所示。
ICMP报文的格式如(图二)所示。
所有的ICMP报文的前4个字节都是一样的,但是其他字节互不相同。
其中0-7位是类型字段,8-15位是代码字段,16-31位是校验和字段。
校验和字段为2个字节,校验的围是整个ICMP报文。
本设计仅用到类型为0和8的ICMP报文,关于这两种类型报文的具体描述详见(图三)。
类型
代码
描述
0
0
回应应答(Ping应答,与类型8的Ping请求一起使用)
8
0
回应请求(Ping请求,与类型8的Ping应答一起使用)
图三:
本设计使用的ICMP报文类型
4.设计法:
本设计使用原始套接字生成ICMP报文来进行活动主机的探测。
设计的大体思想是把包类型设置为回送请求,将它发送给网络上的一个IP地址,如果这个IP地址已被占用,那么使用这个IP地址的主机上的TCP/IP软件就能够接收到这个ICMP回送请求,并返回一个ICMP回送响应信息。
由于接收到的回送响应ICMP包是封装在IP包,就需要解析该IP包,从中找到ICMP数据信息。
相反,如果这个IP地址没有人使用,那么发送的ICMP回送请求在设定的时延就不可能得到响应。
在初始化原始套接字后,程序就要开始在一个IP网段寻找活动主机。
由于在某网段需要发现的主机很多,为提高效率,采用了多线程编程。
主程序和子线程的流程图分别如(图四)和(图五)所示。
5.程序流程图:
6.程序清单:
#pragmapack(4)
#pragmacomment(lib,"WS2_32.LIB")
#defineWIN32_LEAN_AND_MEAN
#include
#include
#include
#include
#include
#include
#include
//头文件
typedefstructiphdr{//IP头
unsignedintheadlen:
4;//IP头长度
unsignedintversion:
4;//IP版本号
unsignedchartos;//服务类型
unsignedshortid;//ID号
unsignedshortflag;//标记
unsignedcharttl;//生存时间
unsignedcharprot;//协议
unsignedshortchecksum;//效验和
unsignedintsourceIP;//源IP
unsignedintdestIP;//目的IP
}IpHeader;
//IP头部
typedefstructicmphdr{//ICMP头
BYTEtype;//ICMP类型码
BYTEcode;//子类型码
USHORTchecksum;//效验和
USHORTid;//ID号
USHORTseq;//ICMP数据报的序列号
}IcmpHeader;
//ICMP部
#defineICMP_ECHO8//请求回送
#defineICMP_ECHO_REPLY0//请求回应
#defineICMP_MIN8//ICMP长度(最小ICMP包长度)
#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;
//dest:
搜索目的IP,
//from:
接收ICMP包的源IP
//end:
搜索终止IP。
intfromlen=sizeof(from);//接收ICMP包长度
char*recvbuf=newchar[MAX_PING_PACKET_SIZE];//接受ICMP包缓冲区
unsignedintaddr=0;//IP地址
longThreadNumCounter=0,ThreadNumLimit=20;//线程数及最大允线程数
long*aa=&ThreadNumCounter;
//全局变量的申明
voidmain(intargc,char*argv[])
{
if(argc!
=3)//判断格式是否正确
{
cout<<"输入格式错误:
scanhoststart_ipend_ip"<return;
}
if(WSAStartup(MAKEWORD(2,1),&wsaData)!
=0)
{
cout<<"WSAStartupfailed:
"<ExitProcess(STATUS_FAILED);
}
//创建原始套接字
sockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);
if(sockRaw==INVALID_SOCKET)
{
cout<<"WSASocket()failed:
"<ExitProcess(STATUS_FAILED);
}
inttimeout=1000;
intbread=setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));
if(bread==SOCKET_ERROR)
{
cout<<"failedtosetrecvtimeou:
"<ExitProcess(STATUS_FAILED);
}
timeout=1000;
bread=setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));
if(bread==SOCKET_ERROR)
{
cout<<"failedtosetsendtimeout:
"<ExitProcess(STATUS_FAILED);
}
memset(&dest,0,sizeof(dest));//初始化dest结构
unsignedlongstartIP,endIP;
dest.sin_family=AF_INET;
dest.sin_addr.s_addr=inet_addr(argv[1]);//填入开始搜索IP
startIP=inet_addr(argv[1]);
end.sin_family=AF_INET;
end.sin_addr.s_addr=inet_addr(argv[2]);
endIP=inet_addr(argv[2]);//填入结束搜索IP地址
HANDLEhThread;
while(htonl(startIP)<=htonl(endIP))//起始IP比结束IP小
{
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(i--);
TerminateThread(hThread,0);
InterlockedDecrement(aa);
memset(&from,0,sizeof(from));
startIP=htonl(htonl(startIP)+1);
dest.sin_addr.s_addr=startIP;
}
while(ThreadNumCounter!
=0)
{
Sleep(2000);
return;
}
}
voidfill_icmp_data(char*icmp_data,intdatasize)
{
IcmpHeader*icmp_hdr;
char*datapart;
icmp_hdr=(IcmpHeader*)icmp_data;
icmp_hdr->type=ICMP_ECHO;//设置类型信息
icmp_hdr->id=(USHORT)GetCurrentThreadId();//设置其ID号为当前线程ID号
datapart=icmp_data+sizeof(IcmpHeader);//计算ICMP数据报的数据部分
memset(datapart,'A',datasize-sizeof(IcmpHeader));//填入数据
}
//ICMP数据包的填充
voiddecode_resp(char*buf,intbytes,structsockaddr_in*from)
{
IpHeader*iphdr;
IcmpHeader*icmphdr;
unsignedshortiphdrlen;
iphdr=(IpHeader*)buf;
iphdrlen=iphdr->headlen*4;
icmphdr=(IcmpHeader*)(buf+iphdrlen);
if(bytesif(icmphdr->type!
=ICMP_ECHO_REPLY)return;
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);//线程数目+1
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)->seq=0;//序列号置零
((IcmpHeader*)icmp_data)->checksum=checksum((USHORT*)icmp_data,datasize);
//计算效验和后填人
Intbwrote=sendto(sockRaw,icmp_data,datasize,0,(structsockaddr*)pIPAddrTemp,sizeof(dest));
//发送数据报
intn=0;
if(bwrote==SOCKET_ERROR)
{
if(WSAGetLastError()==WSAETIMEDOUT)
{
cout<<"timedout"<}
cout<<"sendtofailed:
"<ExitProcess(STATUS_FAILED);
n=1;
}
if(WSAGetLastError()==WSAETIMEDOUT)
{
cout<<"timedout"<ExitProcess(STATUS_FAILED);
n=1;
}
if(bwrote{
cout<<"Wrote"<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<<"recvfromfailed:
"<ExitProcess(STATUS_FAILED);
n=1;
}
if(n==0)
decode_resp(recvbuf,bread,&from);
InterlockedDecrement(aa);
return0;
}
7.实验步骤及测试
1.建立工程sy4
2.工程中添加文件名为“scanhost”的c++头文件
3.键入头文件scanhost.h文件的容
4.工程中添加文件名为“sy4”的c++源文件
5.键入sy4.cpp源文件的容
6.不断调试至程序正确
7.分别编译头文件和源文件
8.连接两个文件
8.在DOS下运行可执行文件“sy4.exe”
在DOS环境下发命令如下:
c:
\sy4\debug\sy4172.16.201.11172.16.201.18↙
其中sy4.exe是可执行文件。
后面的两个参数表示起始和结束IP地址。
程序执行后可从屏幕中看到所探测到的网段中活动主机的IP地址。
运行结果:
(测试了172.16.201.11到172.16.201.18网段,发现主机无误)
8.总结:
计算机网络是一门新兴的交叉学科,涉及计算机技术与通信技术两个学科。
网络技术经过多年发展,已经形成比较完善的体系。
而且,网络技术还在高速发展中,其应用广泛,知识更新飞快。
对于设计这样一个发展迅速的领域来说,我们课程设计的意义更加重大。
本课程设计主要提高了我两个面的能力:
1,真正理解和掌握处理网络问题的基本法;2,培养了我在网络环境下的编程能力。
通过本次课程设计,我掌握了正确解读网络协议的一般法,懂得了使用C++实现协议并实现指定功能。
通过两个星期的辛勤劳动,我较好接受了网络问题处理的基本思路,掌握网络环境中编程的基本法。
这让我能够更好的接受前人的眼界成果,并在此基础上很好的接受新知识和继续学习,适应网络技术的飞快发展。
以上总结是宏观面的意义。
微观上,本次实验让我很好的理解了ICMP报文的结构,对ICMP协议也有了更好的认识。
实验过程中,我充分感受到了认真谨的重要性。
比如一次输入失误,把CreateThread写为CreateThead,虽然仅有一个r的差别,但是多花了一个多小时的调试时间。
这个意外也让我吸取了教训,编写程序的时候应该规,认真。
实验历时两,期间遇到了各类问题若干。
在此向给我帮助的老师和同学致以深深的意。
没有你们的帮忙,我不可能如此顺利的完成本设计。
9.参考资料:
[1]功宜;计算机网络;清华大学。
[2]功宜 晓英等编著;计算机网络课程设计;机械工业。
[3]揣锦华;面向对象程序设计与VC++实践;电子科技大学。
[4]高传善;数据通信与计算机网络;高等教育。
[5]互连网;ICMP协议简介;.opendigest.org/article.php/65。
[6]互连网;透析ICMP协议;
[6]互连网;WinSock网络编程实用宝典;