admin管理员组

文章数量:1530919

2023年12月22日发(作者:)

沈 阳 工 程 学 院

学 生 实 验 报 告

实验室名称:信息工程系软件实验室

实验课程名称:计算机网络

实验项目名称:ICMP协议应用——Ping解析

班 级:

姓 名:

学 号:

实验日期:2012年04月28日 实验台编号:23

指导教师:

批阅教师(签字): 成绩:

一.实验目的

1) 掌握ICMP原理,体会网络层编程的不同;

2) 理解ICMP报文的作用,了解基本的网络编程框架。

二.实验内容

1) 解析Ping程序的基本实现过程。

2) 体会ICMP协议在Ping程序中的应用。

3) 体会基本的C/S编程框架。

三.实验前的准备

1) 掌握ICMP原理及相关概念。

2) 掌握C语言编程知识。

3) 掌握基本的网络编程内容

四.实验要求及实验软硬件环境

【基本要求】

对Ping程序进行调试并运行实现。

解析ping程序的主要部分,从而体会ICMP协议的应用。

完成此项实验,完成实验报告。

【实验组织方式】

小组实验

【实验条件】

局域网环境下微机二台,编程软件。

五.实验步骤

1.熟悉IP以及ICMP协议的工作机制;

2.熟悉创建原始套接字、IP报头和ICMP报头;

3.体会ICMP协议的作用与特点;

4.调试ICMP协议的Ping实现程序;

5.参加答辩,并撰写实验报告

六.主要程序部分(C++语言实现)

// : 定义控制台应用程序的入口点。

#include

#include

#include

#define SEND_SIZE 32

#define PACKET_SIZE 4096

#define ICMP_ECHO 8

#define ICMP_ECHOREPLY 0

#pragma comment(lib,"Ws2_")

struct icmp

{

unsigned char icmp_type;

//类型

unsigned char icmp_code;

//编码

unsigned short icmp_chksum;

//校验和

unsigned short icmp_id;

//标示符

unsigned short icmp_seq;

//顺序号

unsigned long icmp_data;

//数据

};

struct ip

{

unsigned char ip_hl:4;

//报头长度

unsigned char ip_v:4;

//版本号

unsigned char ip_tos;

//服务类型

unsigned short ip_len;

//总长度

unsigned short ip_id;

//标识

unsigned short ip_off;

//标志

unsigned char ip_ttl;

//生存时间

unsigned char ip_p;

//协议号

unsigned short ip_sum;

//报头校验和

unsigned long ip_src;

//源IP地址

unsigned long ip_dst;

//目的IP地址

};

char sendpacket[PACKET_SIZE];

char recvpacket[PACKET_SIZE];

struct sockaddr_in dest_addr;

struct sockaddr_in from_addr;

int sockfd;

int pid;

unsigned short cal_chksum(unsigned short *addr,int len);

int pack(int pack_no);

int unpack(unsigned char *buf,int len);

void send_packet(void);

void recv_packet(void);

int main(int argc, CHAR* argv[])

{

struct hostent *host;

struct protoent *protocol;

int timeout=1000;

int SEND_COUNT=4;

int i;

char *par_host;

char m_Input[100];

printf("Input IP: ");

gets(m_Input);

par_host=m_Input;

WORD wVersionRequested;

WSADATA wsaData;

int err;

wVersionRequested = MAKEWORD( 2, 2 );

err = WSAStartup( wVersionRequested, &wsaData );

if ( err != 0 ) return;

if ( LOBYTE( on ) != 2 ||

HIBYTE( on ) != 2 ) {

WSACleanup( );

return;

}

if( (protocol=getprotobyname("icmp") )==NULL) //返回对应于给定协议名的包含名字和协议号

{

}

if( (sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto) )<0)

{

printf("socket errorn");

exit(1);

printf("getprotobyname errorn"); //的protoent结构指针

exit(1);

}

if(setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout))<0) //设置套接口的选项

fprintf(stderr,"failed to set recv timeout: %dn",WSAGetLastError());

if(setsockopt(sockfd,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout))<0)

fprintf(stderr,"failed to set send timeout: %dn",WSAGetLastError());

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

dest__family=AF_INET;

if(host=gethostbyname(par_host) ) // 返回对应于给定主机名的主机信息

{

memcpy( (char *)&dest__addr,host->h_addr,host->h_length);

//resolve address to hostname

if(host=gethostbyaddr(host->h_addr,4,PF_INET))

par_host=host->h_name;

}

else if( dest__addr.s_addr=inet_addr(par_host)==INADDR_NONE)

{

}

printf("Unkown host %sn",par_host);

exit(1);

pid=_getpid();

printf("Pinging %s [%s]: with %d bytes of

data:nn",par_host,inet_ntoa(dest__addr),SEND_SIZE);

for(i=0;i

{

}

}

//this algorithm is referenced from other's

unsigned short cal_chksum(unsigned short *addr,int len)

{

int nleft=len;

int sum=0;

unsigned short *w=addr;

unsigned short answer=0;

while(nleft>1)

{ sum+=*w++;

nleft-=2;

}

if( nleft==1) //处理ICMP报头为奇数个字节时累加最后一个

{ *(unsigned char *)(&answer)=*(unsigned char *)w;

sum+=answer;

}

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

sum+=(sum>>16);

answer=~sum;

return answer;

}

//打包

int pack(int pack_no)

send_packet();

recv_packet();

Sleep(1000);

{

int packsize;

struct icmp *icmp;

packsize=8+SEND_SIZE;

icmp=(struct icmp*)sendpacket;

icmp->icmp_type=ICMP_ECHO;

icmp->icmp_code=0;

icmp->icmp_chksum=0;

icmp->icmp_seq=pack_no;

icmp->icmp_id=pid;

icmp->icmp_data=GetTickCount();

icmp->icmp_chksum=cal_chksum( (unsigned short *)icmp,packsize); /*校验算法*/

return packsize;

}

//解包

int unpack(char *buf,int len)

{

struct ip *ip;

struct icmp *icmp;

double rtt;

int iphdrlen;

ip=(struct ip *)buf;

iphdrlen=ip->ip_hl*4;

icmp=(struct icmp *)(buf+iphdrlen);

if( (icmp->icmp_type==ICMP_ECHOREPLY) && (icmp->icmp_id==pid) )

{

len=len-iphdrlen-8;

rtt=GetTickCount()-icmp->icmp_data;

printf("Reply from %s: bytes=%d time=%.0fms TTL=%d

icmp_seq=%un",

inet_ntoa(from__addr),

len,

rtt,

ip->ip_ttl,

icmp->icmp_seq);

return 1;

}

return 0;

}

//发送

void send_packet()

{

int packetsize;

static int pack_no=0;

packetsize=pack(pack_no++);

if( sendto(sockfd,sendpacket,packetsize,0,(struct sockaddr

*)&dest_addr,sizeof(dest_addr) )<0 )

printf("Destination host unreachable.n");

// printf("send NO %dn",pack_no-1);

}

//接收

void recv_packet()

{

int n,fromlen;

int success;

fromlen=sizeof(from_addr);

do

{

if( (n=recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr

*)&from_addr,&fromlen)) >=0)

success=unpack(recvpacket,n);

else if (WSAGetLastError() == WSAETIMEDOUT)

{

printf("Request timed out.n");

return;

}

}while(!success);

}

七.结果分析

运行结果如图1所示:

图1 运行结果

运行结果可看出此程序不断地在向172.20.72.12发送数据包,并且得到了应答。

八.个人总结

本次课程设计较好地实现了要求做到的功能,但同时也遇到不少的困难和挑战。通过本次实验我们了解到 ICMP协议是一个非常重要的协议,它对于网络安全、网络的正常运作具有极其重要的意义,它被用于在IP主机、路由器之间传递控制消息,如网络通不通、主机是否可达、路由是否可用等。实验中将原始数据在网络层添加IP报头和数据链路层添加ICMP的报头,再在目的端解封装这两个报头。通过这次实验,我们不但加深了对Socket的原始套接字RAW编程的理解,同时也对IP和ICMP协议有了进一步的认识。

教师签字: 年 月 日

本文标签: 实验协议报头编程程序