Ping命令源代码
- 格式:doc
- 大小:28.50 KB
- 文档页数:7
ping命令的实现过程-回复"ping命令的实现过程"引言:在计算机网络中,ping命令是一种常见的网络诊断工具,用于测试主机之间的连接性以及网络延迟。
它通过发送ICMP(Internet Control Message Protocol)请求报文,并等待目标主机返回相应。
本文将一步一步地解析ping命令的实现过程,帮助读者深入了解这个常用工具背后的原理。
一、环境准备要实现ping命令,我们首先需要了解网络协议栈和操作系统网络接口的基本知识。
同时,为了简化实现过程,我们将使用一些常见的网络库、工具和编程语言,例如Python或C语言的套接字编程接口。
二、发送ICMP请求报文在实现ping命令时,我们要首先构造ICMP请求报文,并通过网络发送给目标主机。
这个过程可以分为以下几个步骤:1. 创建套接字:使用socket库创建一个原始套接字,以便可以直接访问网络层。
通常,这个套接字的协议类型应为ICMP。
2. 构造IP报文头:创建IP报文头以封装ICMP请求报文。
这需要设置源IP地址、目标IP地址以及其他相关网络参数。
3. 构造ICMP请求报文:创建ICMP请求报文,其中包括报文类型(通常为Echo Request)、标识符(用于匹配请求和响应报文)、序列号(用于区分不同的ping请求)等字段。
还要计算校验和,确保报文的完整性。
4. 发送报文:通过上述套接字将构造的IP报文头和ICMP请求报文发送给目标主机。
三、接收ICMP响应报文发送ICMP请求报文后,我们需要等待目标主机的响应,并分析返回的ICMP响应报文。
下面是实现这一步的具体过程:1. 准备套接字:在接收ICMP响应报文之前,我们首先需要准备接收这些报文的套接字。
同样,我们使用一个原始套接字,并设置其协议类型为ICMP。
2. 接收报文:使用套接字的接收函数,等待目标主机的ICMP响应报文,并将其存储在缓冲区中。
3. 解析报文:解析接收到的ICMP响应报文,提取其中的关键信息,如标识符、序列号以及时间戳等。
一、ping命令详解在日常网络维护工作中,我们使用最多的工具可能就是ping命令了,下面就ping命令的原理与应用进行介绍。
(一)Ping命令原理?????了解ping命令的原理能够更好的利用这个测试工具。
?????1.pingPing的网络在网络传输过程中,可能会发生许多突发事件并导致数据传输失败。
网络层的IP协议是一个无连接的协议,它不会处理网络层传输中的故障,而位于网络层的ICMP协议却恰好弥补了IP的缺限,ICMP消息被封装为IP数据包后传输,收到ICMP消息的主机向数据包中的源主机提供发生在网络层的通信结果或者错误信息反馈。
如果中间节点出现通信中断,中间节点的ICMP协议能够响应ICMP测试消息,在源主机通过观察ICMP 响应消息的源地址,能够快速定位通信在哪一个节点被中断了,也可以通过响应消息判断大致的故障原因。
4、ICMP协议ICMP注意类型和代码为(8,0)的为ping请求包,也称echorequest类型和代码为(0,0)的为ping应答包,也称echoreply其它类型和代码为扩展功能和报错消息。
6、结束语通过本文的介绍,我们可以了解到ping命令使用ICMP协议工作,ICMP的ip协议号为1,通过ICMP 报文类型和代码的介绍,可以了解到更多的ping命令功能和报错消息,并且以后如果需要使用ACL控制各种ping 操作,可以参考这些类型和代码进行准确的控制。
一、ping命令--详细帮助校验与远程计算机或本地计算机的连接。
只有在安装TCP/IP协议之后才能使用该命令。
ping[-t][-a][-ncount][-llength][-f][-ittl][-vtos][-rcount][-scount][[-jcomputer-list]|[-kcomputer参数-t-a-ncount发送由-f-ittl将“-vtos将“-rcount在“。
-scount指定由count指定的转发次数的时间邮票。
1)PING的关键源代码:<基于VC++编译的。
应用于ARM >< xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" /> void CEPing(CString cIPAddr,CListBox * pListBox,CWnd * pWnd){WSAData wsaData;//初始化Socket动态链接库if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0){return ;}/*将IP地址转换成单字节*/char szDestIPAddr[255];ZeroMemory(szDestIPAddr,255);WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,cIPAddr.GetBuffer(cIPAddr.GetLength()),cIPAddr.GetLength(),szDestIPAddr,cIPAddr.GetLength(),NULL,NULL);IPAddr ipAddr;//将目标字符串IP地址转换成IPAddr结构ipAddr = inet_addr(szDestIPAddr);if (ipAddr == INADDR_NONE){AfxMessageBox(TEXT("地址无效"));return ;}// 打开ping服务HANDLE hIP = IcmpCreateFile();if (hIP == INVALID_HANDLE_VALUE){AfxMessageBox(TEXT("不能打开Ping服务"));return ;}// 构造ping数据包char acPingBuffer[64];memset(acPingBuffer, '*', sizeof(acPingBuffer));PICMP_ECHO_REPLY pIpe =(PICMP_ECHO_REPLY)GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(ICMP_ECHO_REPLY) + sizeof(acPingBuffer));if (pIpe == 0){AfxMessageBox(TEXT("分配ping包缓冲区失败"));return ;}CString m_recv;// 发送ping数据包m_recv = "ping "+cIPAddr+" with 64 Bytes";pListBox->AddString(m_recv);for (int i=0;i<4;i++){//发送ping服务包,等待接收时间为1秒DWORD dwStatus = IcmpSendEcho(hIP,ipAddr,acPingBuffer, sizeof(acPingBuffer), NULL, pIpe,sizeof(ICMP_ECHO_REPLY) + sizeof(acPingBuffer), 1000);//当dwStatus不等于0,代表接收到回应if (dwStatus != 0){m_recv.Format(TEXT("Reply From %d.%d.%d.%d :bytes=%d time=%d TTL"),int(LOBYTE(LOWORD(pIpe->Address))),int(HIBYTE(LOWORD(pIpe->Address))),int(LOBYTE(HIWORD(pIpe->Address))),int(HIBYTE(HIWORD(pIpe->Address))),int(pIpe->DataSize),int(pIpe->RoundTripTime),int(pIpe->Options.Ttl));pListBox->AddString(m_recv);Sleep(500);}else{pListBox->AddString(TEXT("Error obtaining info from ping packet."));}pWnd->UpdateWindow();}//释放已分配的内存GlobalFree(pIpe);//关闭Ping服务IcmpCloseHandle(hIP);//释放Socket资源WSACleanup();}void CPingDlg::OnBtnClear(){// TODO: Add your control notification handler code hereint nCount = m_lstRecv.GetCount();for (int i=0;i < nCount;i++){m_lstRecv.DeleteString(0);}}void CPingDlg::OnBtnPing(){// TODO: Add your control notification handler code hereUpdateData(TRUE);CEPing(m_ipAddr,&m_lstRecv,this);UpdateWindow();}。
ping 源码分析10.4.1 ping简介Ping是网络中应用非常广泛的一个软件,它是基于ICMP协议的。
下面首先对ICMP协议做一简单介绍。
ICMP是IP层的一个协议,它是用来探测主机、路由维护、路由选择和流量控制的。
ICMP 报文的最终报宿不是报宿计算机上的一个用户进程,而是那个计算机上的IP层软件。
也就是说,当一个带有错误信息的ICMP报文到达时,IP软件模块就处理本身问题,而不把这个ICMP报文传送给应用程序。
ICMP报文类型有:回送(ECHO)回答(0);报宿不可到达(3);报源断开(4);重定向(改变路由)(5);回送(ECHO)请求(8);数据报超时(11);数据报参数问题(12);时间印迹请求(13);时间印迹回答(14);信息请求(15);信息回答(16);地址掩码请求(17);地址掩码回答(18)。
虽然每种报文都有不同的格式,但它们开始都有下面三段:∙ 一个8位整数报文TYPE(类型)段;∙ 一个8位CODE(代码码)段,提供更多的报文类型信息;∙ 一个16 位CHECKSUM(校验和)段;此外,报告差错的ICMP 报文还包含产生问题数据报的网际报头及前64 位数据。
一个ICMP回送请求与回送回答报文的格式如表10.17 所示。
表10.17 ICMP回送请求与回送回答报文格式类型CODE 校验和[CHECKSUM]标识符序列号《嵌入式Linux应用程序开发详解》——第10章、嵌入式Linux网络编程数据10.4.2 ping源码分析下面的ping.c 源码是在busybox 里实现的源码。
在这个完整的ping.c 代码中有较多选项的部分代码,因此,这里先分析除去选项部分代码的函数实现部分流程,接下来再给出完整的ping代码分析。
这样,读者就可以看到一个完整协议实现应该考虑到的各个部分。
1.Ping 代码主体流程Ping.c主体流程图如下图10.8 所示。
另外,由于ping是IP层的协议,因此在建立socket时需要使用SOCK_RAW 选项。
python实现ping命令⼩程序ping的原理是发送⼀个ICMP请求包,然后根据⽬的地址的应答包来判断是否能够和这个主机进⾏通信。
我们使⽤python实现,借助于scapy来进⾏编写程序。
from scapy.all import *import time,struct,random# 编写ping⼀个包的函数。
def ping_one(dst = '36.152.44.95',ttl_no = 64,id_no = 345,seq_no = 5):start_time = time.time()# 将时间转换为⼆进制序列。
time_to_bytes = struct.pack('>d',start_time)# 进⾏发送ICMP包,发送出去⼀个,收回来⼀个。
ping_one_result = sr1(IP(dst = dst,ttl = ttl_no)/ICMP(seq = seq_no,id = id_no)/time_to_bytes, timeout = 1, verbose=False)# print(ping_one_result.show())# 判断收回来的包是不是ICMP的应答包,和序列号是否相同。
try:if ping_one_result.getlayer('ICMP').type == 0 and ping_one_result.getlayer('ICMP').seq == seq_no:# print('进⾏解析包')# 提取IP头部中的源IP地址,也就是我们ping的IP地址。
reply_src_IP = ping_one_result.getlayer('IP').src# 提取序列号。
reply_icmp_seq = ping_one_result.getlayer('ICMP').seq# 提取ttlreply_icmp_ttl = ping_one_result.getlayer('IP').ttl# 数据长度等于数据长度(Raw) + 垫⽚长度(Padding) + 8字节(ICMP头部长度)if ping_one_result.getlayer(Raw) != None:Raw_length = len(ping_one_result.getlayer(Raw).load)else:Raw_length = 0if ping_one_result.getlayer(Padding) != None:Padding_length = len(ping_one_result.getlayer(Padding).load)else:Padding_length = 0# 计算数据长度。
一、实验题目编程模拟ping程序,实现Ping程序的基本功能,即接收到一个ping程序数据包后给出回应。
二、原理概述ping命令是用来查看网络上另一个主机系统的网络连接是否正常的一个工具。
ping命令的工作原理是:向网络上的另一个主机系统发送ICMP报文,如果指定系统得到了报文,它将把报文一模一样地传回给发送者,这有点象潜水艇声纳系统中使用的发声装置。
想要了解ping命令的原理必须了解ICMP协议、ICMP报文格式和IP报文格式。
(1)ICMP报文结构ICMP 报文结构: ICMP 报文前四个字节为报文头部分,第一个字节为报文类型,第二个字节未用, 第三四个字节为报文的校验和。
从第四个字节开始为长度可变的数据段,该段的内容取决于ICMP 的类型,本文所要使用的请求报文和请求应答报文的数据段中前四个字节是报文的标识符和顺序号。
对于整个ICMP 报文来说其长度最长不能超过64K字节。
ICMP 报文结构如图1 所示。
0 7 8 15 16 31 32 47 48 63 64(2)IP报文结构ICMP 报文和其它位于IP 层的报文一样是作为IP 报文的数据段加上IP 报文头组成IP 数据报发出,其中IP 报文头长度一般为20 个字节。
如图2所示。
三、设计方案根据实验题目查找相关资料,熟悉及理解ping的工作原理,从而进一步设计ping程序的功能图和系统流程图。
准备工作做好后就可上机调试,验证其可行性并查找漏洞,完善ping程序。
(1) ping程序的设计包含了4部分:IP、ICMP的头结构,主函数模块,CMP数据包校验和的计算和使用说明模块。
(2)系统流程图首先在主函数里定义变量同时进行初始化,然后检查参数的正确性,如果参数不正确或者没有输入参数,则显示用户帮助信息(Usage ),并结束程序;如果参数正确,则对指定目的地执行Ping命令,如果Ping通,则显示Ping结果并释放占用资源,如果没有Ping通,则报告错误信息,并释放占用资源。
[liunx,ping命令大全] liunx命令大全Ping 是Windows系列自带的一个可执行命令。
利用它可以检查网络是否能够连通,用好它可以很好地帮助我们分析判定网络故障。
接下来是小编为大家收集的liunx ping命令大全,欢迎大家阅读:liunx ping命令大全应用格式:Ping IP地址。
该命令还可以加许多参数使用,具体是键入Ping按回车即可看到详细说明。
#1 1.Ping本机IP例如本机IP地址为:172.168.200.2。
则执行命令Ping 172.168.200.2。
如果网卡安装配置没有问题,则应有类似下列显示:Replay from 172.168.200.2 bytes=32 time<10msPing statistics for 172.168.200.2Packets Sent=4 Received=4 Lost=0 0% lossApproximate round trip times in milli-secondsMinimum=0ms Maxiumu=1ms Average=0ms如果在MS-DOS方式下执行此命令显示内容为:Request timed out,则表明网卡安装或配置有问题。
将网线断开再次执行此命令,如果显示正常,则说明本机使用的IP地址可能与另一台正在使用的机器IP地址重复了。
如果仍然不正常,则表明本机网卡安装或配置有问题,需继续检查相关网络配置。
#1 2.Ping网关IP假定网关IP为:172.168.6.1,则执行命令Ping 172.168.6.1。
在MS-DOS方式下执行此命令,如果显示类似以下信息:Reply from 172.168.6.1 bytes=32 time=9ms TTL=255Ping statistics for 172.168.6.1Packets Sent=4 Received=4 Lost=0 0% lossApproximate round trip times in milli-secondsMinimum=1ms Maximum=9ms Average=5ms则表明局域网中的网关路由器正在正常运行。
Linux⽹络编程基础(4)--Ping的C代码实现1、背景 在进⾏⽹络编程的时候,通常使⽤的协议有TCP协议,UDP协议。
这些协议在简历套接字之初需要制定套接字的类型,⽐如TCP应当设置为 SOCK_STREAM,UDP对应的套接字应当设置为SOCK_DGRAM。
但是这些套接字并⾮能够提供⽹络所需的全部功能,我们还需要其他的套接字,⽐如原始套接字OCK_RAW。
原始套接字可以提供SOCK_STREAM和SOCK_DGRAM所不及的能⼒。
⽐如:(1)有了原始套接字,进程可以读取ICMPV4、ICMPV6、IGMP等的分组。
正如ping所使⽤的套接字,就是SOCK_RAW类型的。
这样使得使⽤ICMP和IGMP的程完全能够作为⽤户进程处理,⽽⽆需向内核添加代码。
(2)有了原始套接字,进程可以处理内核不处理其协议字段的IPV4数据报。
(3)有了原始套接字,进程使⽤IP_HDRINCL套接字选项定制⾃⼰的IPV4头部。
当然,上述的三个功能,并不是本⽂都要涉及的;只关注第⼀个能⼒,编写代码,实现ping程序。
2、基本使⽤ a.定义原始套接字与定义其他套接字没有形式上的巨⼤差别。
int sockfd; sockfd = socket(AF_INET, SOCK_RAW, protocol); protocol 的值是型为 IPPROTO_XXX的量,这些量定义在<netinet/in.h>中,⽐如ping使⽤的 IPPROTO_ICMP(关于IPV6的实现,再后续补充)。
只有超级⽤户才可以创建SOCK_RAW类型的套接字。
b. 原始套接字并不存在端⼝的概念。
可以在原始套接字上调⽤bind函数,但是这么做并不常见。
bind函数会设置发送数据报的源IP地址,如果没有使⽤ bind函数,那么内核将出发的借⼝地址作为源地址。
c. 同样,⼀般不会使⽤connect函数,connect函数会指定⽬的地址,但是因为原始套接字不存在端⼝概念,所以connect函数并不重要了。
linux下ping命令的实现源码// ping.c#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <netinet/in.h>#include <netinet/ip.h>#include <netinet/ip_icmp.h>#include <arpa/inet.h>#include <errno.h>#include <signal.h>#include <net/if.h>#include <sys/ioctl.h>#define BUFSIZE 1500#define MAX_WAIT_TIME 5#define MAX_NO_PACKETS 3// Type of the ICMP headertypedef struct icmphdrunsigned char type; // Type of the ICMP unsigned char code; // Code of the ICMP unsigned short checksum; // Checksum of the ICMP unsigned short id; // ID of the ICMPunsigned short sequence; // Sequence of the ICMP} icmphdr;// IP header's structurestruct iphdrunsigned char h_verlen; // length of the header unsigned char tos; // Type of serviceunsigned short total_len; // Total length of packet unsigned short ident; // Unique identifier unsigned short frag_and_flags; // Flagsunsigned char ttl; // Time to liveunsigned char proto; // Protocol (TCP, UDP etc) unsigned short checksum; // IP checksumunsigned int sourceIP; // Source IPunsigned int destIP; // Destination IP};unsigned short checksum (unsigned short *addr, int len);int pack(char *buf, int s, int seq);int send_packet(int sockfd, struct sockaddr_in *addr, char *sendpacket);int recv_packet(int sockfd, char *buf, struct sockaddr_in *addr);int main(int argc, char *argv[])struct hostent *host;struct sockaddr_in addr;int sockfd, size = 50 * 1024, cnt = MAX_NO_PACKETS, i;char sendpacket[BUFSIZE], recvpacket[BUFSIZE];struct sockaddr_in from;int fromlen = sizeof(from);// Check for the argumentsif (argc != 2)printf("Usage: %s hostname/IP address\n", argv[0]);exit(1);}// socketsockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (sockfd < 0)printf("Socket creating error\n");exit(1);}// Get the hostnameif ((host = gethostbyname(argv[1])) == NULL) printf("Hostname error\n");exit(1);}// Make address structurebzero(&addr, sizeof(addr));addr.sin_family = AF_INET;addr.sin_addr = *(struct in_addr *)host->h_addr; addr.sin_port = htons(0);// set socket buffer sizeif (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) == -1)printf("Set socket buffer size error\n");exit(1);}// Send the ICMP packetfor (i = 0; i < cnt; i++)。
C语言如何实现windows的Ping命令
Ping命令是我们经常接触的,那么C语言如何实现windows的Ping命令的呢?下面是店铺收集整理的C语言如何实现windows的Ping命令,希望对大家有帮助~~
C语言实现windows的Ping命令的方法
首先新建一个C控制台程序,然后添加源文件,导入要用到的头文件和库。
定义一个结构体,来表示ICMP报文的头。
各种变量请看下面注释。
然后写一个计算校验和的方法,用来进行校验。
说来惭愧,都快忘了ICMP协议的很多东西了。
接下来是main函数的主体。
包括各种局部变量的定义,加载动态链接库,实现套接字,然后通信等过程。
代码写完后按F5或者Ctrl+F5进行编译运行,然后到工程的Debug目录下找到生成的.exe文件,然后右键,在兼容性中设置以管理员身份运行。
然后在运行文件的目录下,按住shift键右键,在弹出的菜单中选择打开命令行。
如下图。
最后运行ping命令,运行方式和结果如下。
ping命令详解(最新)通过几个Ping命令判断网络故障篇一局域网内电脑不能上网大致可分以下几个原因,系统的IP设置、网卡、路由器网关和线路故障。
排除硬件及线路的故障问题,我们可以利用Ping命令来快速检测网络状况。
首先,我们点击系统中开始里的运行,在运行栏中输入cmd命令,操作系统中的DOS窗口就会弹出,在这里我们可以直观和方便地输入各种DOS命令。
接着,我们可以在DOS里输入Ping 127.0.0.1,该地址是本地循环地址,如发现本地址无法Ping通,就表明本地机TCP/IP协议不能正常工作,此时应检查本机的操作系统安装设置。
如果上面的操作成功,可Ping通的话,我们接下来可以输入IPConfig来查看本地的IP地址,然后Ping该IP(如 192.168.0.100),通则表明网络适配器(网卡或MODEM)工作正常,不通则是网络适配器出现故障,可尝试更换网卡或驱动程序。
然后Ping 一台同网段计算机的IP,不通则表明网络线路出现故障;若网络中还包含有路由器,则应先Ping路由器在本网段端口的IP,不通则此段线路有问题,应检查网内交换机或网线故障。
如果内网计算机能ping通则再Ping欣联的路由器(网关),(如192.168.0.1)如不通,则是路由器出现故障,可更换连接路由器的网线,或用网线将PC机直接连接至路由器,如能ping通,则应检查路由器至交换机的网线故障,如无法ping通,可尝试更换计算机再ping,若还不能 ping通,则应检查路由器故障。
最后,如果到路由器都正常,可再检测一个带DNS服务的网络,在上一步Ping通了目标计算机的IP地址后,仍无法连接到该机,则可Ping该机的网络名,比如Ping ,正常情况下会出现该网址所指向的IP,这表明本机的DNS设置正确而且DNS服务器工作正常,反之就可能是其中之一出现了故障;同样也可通过Ping计算机名检测WINS解析的故障(WINS是将计算机名解析到IP地址的服务)。
大部分人用ping命令只是作为查看另一个系统的网络连接是否正常的一种简单方法。
在这篇文章中,整理将介绍如何用C语言编写一个模拟ping命令功能的程序。
ping命令是用来查看网络上另一个主机系统的网络连接是否正常的一个工具。
ping命令的工作原理是:向网络上的另一个主机系统发送ICMP报文,如果指定系统得到了报文,它将把报文一模一样地传回给发送者,这有点象潜水艇声纳系统中使用的发声装置。
例如,在Linux终端上执行ping localhost命令将会看到以下结果:PING localhost.localdomain (127.0.0.1) from 127.0.0.1 : 56(84) bytes of data.64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=0 ttl=255 time=112 usec64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=1 ttl=255 time=79 usec64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=2 ttl=255 time=78 usec64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=3 ttl=255 time=82 usec--- localhost.localdomain ping statistics ---4 packets transmitted, 4 packets received, 0% packet lossround-trip min/avg/max/mdev = 0.078/0.087/0.112/0.018 ms由上面的执行结果可以看到,ping命令执行后显示出被测试系统主机名和相应IP位置、返回给当前主机的ICMP报文顺序号、ttl生存时间和往返时间rtt(单位是毫秒,即千分之一秒)。
ping实现原理ping命令是用来查看网络上另一个主机系统的网络连接是否正常的一个工具。
ping命令的工作原理是:向网络上的另一个主机系统发送ICMP报文,如果指定系统得到了报文,它将把报文一模一样地传回给发送者,这有点象潜水艇声纳系统中使用的发声装置。
例如,在Linux终端上执行ping localhost命令将会看到以下结果: PING localhost.localdomain (127.0.0.1) from 127.0.0.1: 56(84) bytes of data. 64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=0 ttl=255 time=112 usec 64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=1 ttl=255 time=79 usec 64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=2 ttl=255 time=78 usec 64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=3 ttl=255 time=82 usec --- localhost.localdomain ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max/mdev = 0.078/0.087/0.112/0.018 ms由上面的执行结果可以看到,ping命令执行后显示出被测试系统主机名和相应IP地址、返回给当前主机的ICMP报文顺序号、ttl生存时间和往返时间rtt (单位是毫秒,即千分之一秒)。
实验报告
课程计算机网络课程设计实验名称Ping程序的设计与实现专业班级08级信管(2)班
姓名
学号**********
实验日期2011年11月8日
System.gc();
end=System.currentTimeMillis();
}
public long duration()//计算响应时间的方法
{
return(end-start);
}
public void reset()//重置开始和结束时间
{
start=0; end=0;
}
}
四. 视图如下:
五.实验总结
通过这次实验, 我掌握了Java网络编程中对应的相关基础知识, 知道了ICMP协议以及跟踪运行Java网络包了解网络编程实现的细节问题, 并了解了Ping命令的功能。
我认识了ping 作为一种通信命令, 是IP协议的一部分, 利用他可以检查网络是否能够连通, 它也可以帮助我们分析网络故障。
通过这次实验,我掌握了Java网络编程中对应的相关基础知识,知道了ICMP 协议以及跟踪运行Java网络包了解网络编程实现的细节问题,并了解了Ping命令的功能。
我认识了ping作为一种通信命令,是IP协议的一部分,利用他可以检查网络是否能够连通,它也可以帮助我们分析网络故障。
一、实验目的基于ICMP请求与应答实现ping程序,用来测试网络的可达性。
二、实验要求1、显示ping的字节数(Bytes)2、显示ping的往返时间(Times)3、显示ping的生存时间(TTL)3、网络不可达时显示requested out!三、实验原理Ping命令是用来查看网络上另一个主机系统的网络是否正常的工具。
其原理是:向网络上的另一个主机系统发送ICMP报文,如果指定系统得到了报文,它将报文一模一样地传送给发送者。
其所使用的协议是ICMP,ICMP(网际控制报文协议)的功能很多,ping程序所用的是ICMP请求与应答报文。
具体的实现还是很简单的,首先要考虑IP数据报和ICMP数据报的区别,然后这两种数据报的结构,IP数据报的头部有(版本号,头长度,服务类型,总长度,标识,标志,片偏移,生存时间,上层协议标识,头部校验和,源IP地址,目标IP地址),这里只考虑20字节的头部,然后就是ICMP报文,ICMP的功能不同,他的头部结构也就不同,请求与应答报文的结构:类型(8位),代码(8位),校验和(16位),标识符(16位),进程ID(16位),进程ID(16位),时间(32位),这里的各部分的位数很重要,所需要的生存时间TTL就是从IP数据报头取得的。
四、实验代码#include<iostream>#include <winsock2.h>using namespace std;#pragma comment(lib,"WS2_32")#define DEF_BUF_SIZE 1024#define IP_HEADER_SIZE 20#define ICMP_HEADER_SIZE 12typedef struct _ICMP_HEADER {unsigned char bType; //(8位)类型unsigned char bCode; //(8位)代码unsigned short nCheckSum; //(16位)校验各unsigned short nId; //(16位)进程IDunsigned short nSequence; //(16位)序号unsigned long nTimeStamp; //(32位)时间}ICMP_HEADER, *PICMP_HEADER;struct IPHeader{unsigned char m_byVerHLen; //4位版本+4位首部长度unsigned char m_byTOS; //(8位)服务类型unsigned short m_usTotalLen; //(16位)总长度unsigned short m_usID; //(16位)标识unsigned short m_usFlagFragOffset; //3位标志+13位片偏移unsigned char m_byTTL; //TTLunsigned char m_byProtocol; //协议unsigned short m_usHChecksum; //首部检验和unsigned long m_ulSrcIP; //(32位)源IP地址unsigned long m_ulDestIP; //(32位)目的IP地址};//计算校验和(二进制反码求和)unsigned short checksum(PICMP_HEADER picmp,int length){ //length表示icmp回送请求报文的长度long sum=0;unsigned short *icmp=(unsigned short*)picmp;while(length>1){sum+=*icmp++;sum=(sum&0xffff)+(sum>>16); //与高16位的进位数相加length-=2;}if(length==1){ // 报文长度为奇数,最后剩下一个字节sum+=*(unsigned char*)icmp;}while(sum>>16) //进位数与部分和求和sum=(sum&&0xffff)+(sum>>16);return (unsigned short)~sum; //取反}USHORT GetCheckSum(LPBYTE lpBuff, DWORD dwSize) {DWORD dwCheckSum = 0;USHORT* lpWord = (USHORT*)lpBuff;while(dwSize > 1) {dwCheckSum += *lpWord++;dwSize -= 2;}if(dwSize ==1)dwCheckSum += *((LPBYTE)lpBuff);dwCheckSum = (dwCheckSum >> 16) + (dwCheckSum & 0XFFFF);return (USHORT)(~dwCheckSum);}bool Ping(char* lpDestIP) {sockaddr_in DestSockAddr;DestSockAddr.sin_family = AF_INET;DestSockAddr.sin_addr.S_un.S_addr = inet_addr(lpDestIP);DestSockAddr.sin_port = htons(0);char ICMPPack[ICMP_HEADER_SIZE] = {0};PICMP_HEADER pICMPHeader = (PICMP_HEADER)ICMPPack;pICMPHeader->bType = 8;pICMPHeader->bCode = 0;pICMPHeader->nId = (unsigned short) GetCurrentProcessId();pICMPHeader->nCheckSum = 0;pICMPHeader->nTimeStamp = 0;WORD version = MAKEWORD(2, 2);WSADATA wsaData;if(WSAStartup(version, &wsaData) != 0){printf("WSAStartup error\n");return FALSE;}SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);int nTime = 1000;//设置接收超时时间int ret = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTime, sizeof(nTime));char szRcvBuff[DEF_BUF_SIZE];sockaddr_in SourceSockAddr;for(int i=0; i <4; i++){pICMPHeader->nCheckSum = 0;pICMPHeader->nSequence = i;pICMPHeader->nTimeStamp = GetTickCount();pICMPHeader->nCheckSum = GetCheckSum((LPBYTE)(ICMPPack), ICMP_HEADER_SIZE);unsigned short x=GetCheckSum((LPBYTE)(ICMPPack), ICMP_HEADER_SIZE);int nRet = sendto(s, ICMPPack, ICMP_HEADER_SIZE, 0, (SOCKADDR*)&DestSockAddr, sizeof(DestSockAddr));if(nRet == SOCKET_ERROR){printf("send error.\n");return FALSE;}int nLen = sizeof(sockaddr_in);if(nRet == SOCKET_ERROR){int nError = WSAGetLastError();printf("Recv Error:%d.\n", nError);return FALSE;}nRet = recvfrom(s, szRcvBuff,DEF_BUF_SIZE,0,(SOCKADDR*)&SourceSockAddr,&nLen);if(nRet == SOCKET_ERROR){cout<<"Request timed out!"<<endl;}else{IPHeader *pIPHeader = (IPHeader*)szRcvBuff;PICMP_HEADER pRcvHeader = (PICMP_HEADER)(szRcvBuff + IP_HEADER_SIZE);int nTime = GetTickCount() - pRcvHeader->nTimeStamp;printf("从目标地址传回: %s bytes=%d time=%dms TTL=%d\n", inet_ntoa(SourceSockAddr.sin_addr), nRet, nTime,pIPHeader->m_byTTL);}Sleep(1000);}closesocket(s);WSACleanup();return TRUE;}void main(){while(1){cout<<"输入IP地址:";char ip[20];cin>>ip;Ping(ip);cout<<endl<<endl;}}五、实验截图1、自己写的ping程序。
icmp类型代码ICMP类型代码的详细介绍ICMP是Internet控制消息协议的缩写,用于传送控制信息和错误消息。
该协议通常被解释为与TCP/IP协议族同等重要的协议。
该协议是用于在IP网络上测试网络的有效性和状态。
可将ICMP视为TCP/IP的传输层之下。
ICMP有许多类型代码,每个代码都有特定的目的和功能,重要的几个类型是:1. Echo Request/Reply(PING)(类型代码8/0)8是echo request,它是一种用于测试网络连通性的消息类型。
用于发送到目标主机并返回响应的答案。
这个消息类型相当于向目标主机发送一个“你在哪里”的请求,并希望它能回答“我在这里”。
0是echo reply,它是ping命令的返回,因此可以确定主机是否接受。
该消息类型为请求发出方指定并由接收方响应。
2. Destination Unreachable(类型代码3)这个ICMP类型代码通常出现在当IP包无法路由或当目标主机处于无响应状态时,因为某些原因(可能是一个防火墙拒绝了连接),该类型消息是一个错误消息,目的是告诉发送方它所发送的信息无法到达目标位置。
3. Redirect(类型代码5)当路由器收到一条报文并确定该报文的下一次跃点不是下一条发送方应该发送到的路由器时,它将向发送方发送“重定向”消息,告诉发送方要转发该报文的新路由器。
该消息对于减少本地流量是非常有用的。
4. Source Quench(类型代码4)当接收方可能总是无法处理所接收到的数据包时,它会向发送方发送源减弱消息(当然这不是他想要的结果)。
发送方收到此消息后,将减缓其发送速度,并尝试重新发送。
5. Time Exceeded(类型代码11)当一条消息在到达目标主机前超过了其最大生存时间(TTL)时,发送方将收到一条“时间超时”的消息。
ICMP类型代码是对控制消息和错误消息的分类,这些消息可以告诉网络管理员网络的状况。
尤其是在故障调试时,这些消息可以节约学习时间和努力的宝贵资源。
ping的原理就是首先建立通道,然后发送包,对方接受后返回信息,这个包至少包括以下内容,发送的时候,包的内容包括对方的ip地址和自己的地址,还有序列数,回送的时候包括双方地址,还有时间等,主要是接受方在都是在操作系统内核里做好的,时刻在监听,提供一段c程序的代码,希望对大家有用。
#include#include#include#include#include#include#include#include#include#include#include#include#define PACKET_SIZE 4096#define MAX_WAIT_TIME 5#define MAX_NO_PACKETS 3char sendpacket[PACKET_SIZE];char recvpacket[PACKET_SIZE];int sockfd,datalen=56;int nsend=0,nreceived=0;struct sockaddr_in dest_addr;pid_t pid;struct sockaddr_in from;struct timeval tvrecv;void statistics(int signo);unsigned short cal_chksum(unsigned short *addr,int len);int pack(int pack_no);void send_packet(void);void recv_packet(void);int unpack(char *buf,int len);void tv_sub(struct timeval *out,struct timeval *in);void statistics(int signo){ printf("\n--------------------PING statistics-------------------\n");printf("%d packets transmitted, %d received , %%%d lost\n",nsend,nreceived, (nsend-nreceived)/nsend*100);close(sockfd);exit(1);}/*校验和算法*/unsigned short cal_chksum(unsigned short *addr,int len){ int nleft=len;int sum=0;unsigned short *w=addr;unsigned short answer=0;/*把ICMP报头二进制数据以2字节为单位累加起来*/while(nleft>1){ sum+=*w++;nleft-=2;}/*若ICMP报头为奇数个字节,会剩下最后一字节。
把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加*/if( nleft==1){ *(unsigned char *)(&answer)=*(unsigned char *)w;sum+=answer;}sum=(sum>>16)+(sum&0xffff);sum+=(sum>>16);answer=~sum;return answer;}/*设置ICMP报头*/int pack(int pack_no){ int i,packsize;struct icmp *icmp;struct timeval *tval;icmp=(struct icmp*)sendpacket;icmp->icmp_type=ICMP_ECHO;icmp->icmp_code=0;icmp->icmp_cksum=0;icmp->icmp_seq=pack_no;icmp->icmp_id=pid;packsize=8+datalen;tval= (struct timeval *)icmp->icmp_data;gettimeofday(tval,NULL); /*记录发送时间*/icmp->icmp_cksum=cal_chksum( (unsigned short *)icmp,packsize); /*校验算法*/ return packsize;}/*发送三个ICMP报文*/void send_packet(){ int packetsize;while( nsend{ nsend++;packetsize=pack(nsend); /*设置ICMP报头*/if( sendto(sockfd,sendpacket,packetsize,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr) )<0 ){ perror("sendto error");continue;}sleep(1); /*每隔一秒发送一个ICMP报文*/}}/*接收所有ICMP报文*/void recv_packet(){ int n,fromlen;extern int errno;signal(SIGALRM,statistics);fromlen=sizeof(from);while( nreceived{ alarm(MAX_WAIT_TIME);if( (n=recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from,&fromlen)) <0){ if(errno==EINTR)continue;perror("recvfrom error");continue;}gettimeofday(&tvrecv,NULL); /*记录接收时间*/if(unpack(recvpacket,n)==-1)continue;nreceived++;}}/*剥去ICMP报头*/int unpack(char *buf,int len){ int i,iphdrlen;struct ip *ip;struct icmp *icmp;struct timeval *tvsend;double rtt;ip=(struct ip *)buf;iphdrlen=ip->ip_hl<<2; /*求ip报头长度,即ip报头的长度标志乘4*/ icmp=(struct icmp *)(buf+iphdrlen); /*越过ip报头,指向ICMP报头*/ len-=iphdrlen; /*ICMP报头及ICMP数据报的总长度*/if( len<8) /*小于ICMP报头长度则不合理*/{ printf("ICMP packets\'s length is less than 8\n");return -1;}/*确保所接收的是我所发的的ICMP的回应*/if( (icmp->icmp_type==ICMP_ECHOREPLY) && (icmp->icmp_id==pid) ) { tvsend=(struct timeval *)icmp->icmp_data;tv_sub(&tvrecv,tvsend); /*接收和发送的时间差*/rtt=_sec*1000+_usec/1000; /*以毫秒为单位计算rtt*//*显示相关信息*/printf("%d byte from %s: icmp_seq=%u ttl=%d rtt=%.3f ms\n",len,inet_ntoa(from.sin_addr),icmp->icmp_seq,ip->ip_ttl,rtt);}else return -1;}main(int argc,char *argv[]){ struct hostent *host;struct protoent *protocol;unsigned long inaddr=0l;int waittime=MAX_WAIT_TIME;int size=50*1024;if(argc<2){ printf("usage:%s hostname/IP address\n",argv[0]);exit(1);}if( (protocol=getprotobyname("icmp") )==NULL){ perror("getprotobyname");exit(1);}/*生成使用ICMP的原始套接字,这种套接字只有root才能生成*/if( (sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto) )<0){ perror("socket error");exit(1);}/* 回收root权限,设置当前用户权限*/setuid(getuid());/*扩大套接字接收缓冲区到50K这样做主要为了减小接收缓冲区溢出的的可能性,若无意中ping一个广播地址或多播地址,将会引来大量应答*/ setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size) ); bzero(&dest_addr,sizeof(dest_addr));dest_addr.sin_family=AF_INET;/*判断是主机名还是ip地址*/if( inaddr=inet_addr(argv[1])==INADDR_NONE){ if((host=gethostbyname(argv[1]) )==NULL) /*是主机名*/{ perror("gethostbyname error");exit(1);}memcpy( (char *)&dest_addr.sin_addr,host->h_addr,host->h_length); }else /*是ip地址*/memcpy( (char *)&dest_addr,(char *)&inaddr,host->h_length);/*获取main的进程id,用于设置ICMP的标志符*/pid=getpid();printf("PING %s(%s): %d bytes data in ICMP packets.\n",argv[1], inet_ntoa(dest_addr.sin_addr),datalen);send_packet(); /*发送所有ICMP报文*/recv_packet(); /*接收所有ICMP报文*/statistics(SIGALRM); /*进行统计*/return 0;}/*两个timeval结构相减*/void tv_sub(struct timeval *out,struct timeval *in){ if( (out->tv_usec-=in->tv_usec)<0){ --out->tv_sec;out->tv_usec+=1000000;}out->tv_sec-=in->tv_sec;}。