ping命令的一般格式为:
ping [-dfnqrRv][-c 发送次数][-i 间隔秒数][-I 网络界面][-l 前置载入][-p 范本样式][-s 数据包大小][-t 存活数值][主机名或IP地址]
参数说明:
-d 使用Socket的SO_DEBUG功能。
-f 极限检测。大量且快速地送网络封包给一台机器,看它的回应。
-n 只输出数值。
-q 不显示任何传送封包的信息,只显示最后的结果。
-r 忽略普通的Routing Table,直接将数据包送到远端主机上。通常是查看本机的网络接口是否有问题。
-R 记录路由过程。
-v 详细显示指令的执行过程。
-c 数目 在发送指定数目的包后停止。
-i 秒数 设定间隔几秒送一个网络封包给一台机器,预设值是一秒送一次。
-I 网络界面 使用指定的网络界面送出数据包。
-l 前置载入 设置在送出要求信息之前,先行发出的数据包。
-p 范本样式 设置填满数据包的范本样式。
-s 字节数 指定发送的数据字节数,预设值是56,加上8字节的ICMP头,一共是64ICMP数据字节。
-t 存活数值 设置存活数值TTL的大小。
:linux下的ping和windows下的ping稍有区别,linux下ping不会自动终止,需要按ctrl+c终止或者用参数-c指定要求完成的回应次数
linux下测试本机与目标主机连通性的命令是ping,这里主要讲解两个参数 –c 与 – i
其中 –c count 次数,也就是ping的次数
-i interval 间隔 ,每次ping之间的时间空格
介绍一下ping原理
ping程序实现
@头文件common.h定义,包含程序中用到的头文件及公共变量、宏、常量、静态变量定义
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define IP_HEAD_LEN 20
#define ICMP_LEN 8
#define BUFFER_SIZE 50 * 1024
/*
* 原始套接字的描述符,由于需要在信号处理器
* 和主程序中共享,所以定义为外部变量(全局)
*/
int ip_fd;
/*进程号*/
int p_id;
/*packet_len为IP包头和ICMP包头长度之和*/
extern int packet_len;
/*对端地址*/
struct sockaddr_in send_addr;
/*发送应用缓冲区*/
char send_buf[1024];
/*报文序列号*/
extern int sequence;
/*主机名指针*/
struct hostent *host;
/*标识是否已经接收到回文*/
int flag;
@主函数main.c定义
#include "common.h"
main(int argc, char **argv)
{
/*命令是ping host(主机名)|ip_address(ip地址)*/
if(argc != 2)
{
/*命令不正确*/
fprintf(stderr, "usage: ping
exit(1);
}
/*创建使用ICMP的原始套接字,这种套接字只有root才能生成*/
ip_fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(ip_fd < 0)
{
fprintf(stderr, "raw socket error.n");
exit(1);
}
/*改变进程的用户ID, 回收root权限,设置当前用户权限*/
setuid(getpid());
ping(argv[1]);
}
@ping框架的建立ping.c用于初始化ping相关信息及端口信息
#include "common.h"
/*
*handle_alarm用于定时发送IP数据包
*/
void handle_alarm(int signo)
{
send_ip();
alarm(1);
}
ping(char *argv)
{
struct sigaction act;
act.sa_handler = handle_alarm;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGALRM, &act, NULL);
/*获取main的进程id,用于设置ICMP的标志符*/
p_id = getpid();
/*扩大套接字接收缓冲区到50K这样做主要为了减小接收缓冲区溢出的的可能性,若无意中ping一个广播地址或多播地址,将会引来大量应答*/
//setsockopt(ip_fd, SOL_SOCKET, SO_RCVBUF, &BUFFER_SIZE, sizeof(BUFFER_SIZE));
/*只须填写地址信息,不需要指定端口信息,因为原始套接字在传输层之下*/
send_addr.sin_family = AF_INET;
/*判断是主机名还是ip地址*/
if(inet_addr(argv) == INADDR_NONE)
{
/*是主机名*/
if((host = gethostbyname(argv)) == NULL)
{
/*主机名错误*/
perror("get host by name error: unknow host.");
exit(1);
}
memcpy(&send_addr.sin_addr, host->h_addr, host->h_length);
}
else
{
/*是ip地址*/
inet_aton(argv, &send_addr.sin_addr);
}
printf("ping %s(%s) %d(%d) bytes of datan", argv,
inet_ntoa(send_addr.sin_addr), sizeof(struct timeval),
sizeof(struct timeval) + IP_HEAD_LEN + ICMP_LEN);
flag = 0;
/*触发一个SIGALRM信号*/
raise(SIGALRM);
recv_ip();
}
@发送报文send.c,建立ICMP报文并打包为IP数据包,发送
#include "common.h"
int sequence = 0;
int packet_len = IP_HEAD_LEN + ICMP_LEN;
/*
*send_ip用于发送包含ICMP报文的IP数据包
*/
send_ip(void)
{
if(sequence != 0 && !flag)
{
printf("Destination Host Unreachablen");
}
int len;
struct icmphdr *icmp_p;
icmp_p = (struct icmphdr *)send_buf;
/*填写ICMP报文类型*/
icmp_p->type = ICMP_ECHO;
/*填写ICMP报文的代码*/
icmp_p->code = 0;
/*填写ICMP报文的标识符*/
(icmp_p->un).echo.id = p_id;
/*填写ICMP报文的序号,并增加ICMP的序号*/
(icmp_p->un).echo.sequence = sequence ++;
/*记录发送时间*/
gettimeofday((struct timeval*)(icmp_p + 1), NULL);
/*printf("%dn", sizeof(struct icmphdr));
printf("type: %dncode: %dnchecksum: %dnun.echo.id: %dnun.echo.sequence: %dnun.gateway: %dnun.frag.__unused:%d nun.frag.mtu: %dnn", icmp_p->type, icmp_p->code, icmp_p->checksum, (icmp_p->un).echo.id, (icmp_p- >un).echo.sequence, (icmp_p->un).gateway, (icmp_p->un).frag.__unused, (icmp_p->un).frag.mtu);
printf("type: %dncode: %dnchecksum: %dnun.echo.id: %dnun.echo.sequence: %dnun.gateway: %dnun.frag.__unused: %d nun.frag.mtu: %dnn", sizeof(icmp_p->type), sizeof(icmp_p->code), sizeof(icmp_p->checksum), sizeof((icmp_p- >un).echo.id), sizeof((icmp_p->un).echo.sequence), sizeof((icmp_p->un).gateway), sizeof((icmp_p->un).frag.__unused), sizeof((icmp_p->un).frag.mtu));*/
/*报文的长度等于IP包长度加上ICMP报文长度和数据长度*/
len = sizeof(struct timeval) + packet_len;
/*使用IP计算IP包头校验和的计算方法来计算ICMP的校验和*/
icmp_p->checksum = 0;
icmp_p->checksum = ip_checksum((u_short *)icmp_p, len);
/*发送IP数据包*/
if(sendto(ip_fd, send_buf, len, 0, (struct sockaddr*)&send_addr, sizeof(send_addr)) < 0)
{
fprintf(stderr, "send to error.n");
}
}
@数据校验check_sum.c实现网络数据的校验工作
#include "common.h"
unsigned short ip_checksum(unsigned short *pcheck, int check_len)
{
int nleft = check_len;
int sum = 0;
unsigned short *p = pcheck;
unsigned short result = 0;
while(nleft > 1)
{
sum = sum + *p ++;
nleft -= 2;
}
if(nleft == 1)
{
*(unsigned char *)(&result) = *(unsigned char *)p;
sum += result;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = sum;
return result;
}
@数据包接收receive.c,接收IP报文并分析,打印相关信息
#include "common.h"
/*
*recv_ip用于接受包含ICMP报文的IP数据包
*/
recv_ip(void)
{
char recv_buf[1024];
int len;
int n;
struct ip *ip_p;
struct timeval *time_now, *time_send;
struct timeval now;
int iphead_len;
int icmp_len;
struct icmphdr *icmp_p;
float delay;
while(1)
{
n = recvfrom(ip_fd, recv_buf, sizeof(recv_buf), 0, NULL, NULL);
if(n < 0)
{
if(errno = EINTR)
continue;
else
{
printf("recvfrom error.n");
continue;
}
}
ip_p = (struct ip*)recv_buf;
/*获取IP包头长度*/
iphead_len = ip_p->ip_hl<<2;
/*获取IP数据包中包含的ICMP报文*/
icmp_p = (struct icmphdr *)(recv_buf + iphead_len);
/*计算ICMP报文长度,它等于接受到的长度减去IP包头的长度*/
icmp_len = n - iphead_len;
if(icmp_len < 8)
{
fprintf(stderr, "error icmp len = %d.n", icmp_len);
}
/*如果ICMP类型相同则输出显示*/
if(icmp_p->type == ICMP_ECHOREPLY)
{
if((icmp_p->un).echo.id != p_id)
return;
if(icmp_len < 16)
printf("icmplen = %d.n", icmp_len);
flag = 1;//表示已经接收到回文;
gettimeofday(&now, NULL);
time_now = &now;
time_send = (struct timeval*)(icmp_p + 1);
if((time_now->tv_usec -= time_send->tv_usec) < 0)
{
time_now->tv_sec --;
time_now->tv_usec += 1000000;
}
time_now->tv_sec -= time_send->tv_sec;
/*计算延时*/
delay = time_now->tv_sec * 1000.0 + time_now->tv_usec / 1000.0;
/*打印接收到的报文相关信息*/
printf("%d(%d) bytes from %s: icmp_seq=%d ttl=%d time=%.3fmsn",
icmp_len, n, inet_ntoa(send_addr.sin_addr), (icmp_p->un).echo.sequence,
ip_p->ip_ttl, delay);
}
}
}
@makefile文件
#小型ping程序
#用c语言编写
#2008年03月30日
cc = gcc
obj = main.o ping.o send.o receive.o check_sum.o
ping:$(obj)
$(cc) $(obj) -o ping
main.o:main.c common.h ping.c
$(cc) -c main.c
ping.o:ping.c common.h receive.c send.c
$(cc) -c ping.c
send.o:send.c common.h check_sum.c
$(cc) -c send.c
receive.o:receive.c common.h
$(cc) -c receive.c
check_sum.o:check_sum.c common.h
$(cc) -c check_sum.c
clean:
rm -f $(obj)
参考文献:《linux网络编程》
林宇 郭凌云 编著
人民邮电出版社出版
进入makefile所在目录
执行make -f makefile
make clean即可
程序运行结果:(平台ubuntu)
lwj@lwj-desktop:~/Desktop/C/myping$ make -f makefile
gcc -c main.c
gcc -c ping.c
gcc -c send.c
gcc -c receive.c
gcc -c check_sum.c
gcc main.o ping.o send.o receive.o check_sum.o -o ping
lwj@lwj-desktop:~/Desktop/C/myping$ make clean
rm -f main.o ping.o send.o receive.o check_sum.o
lwj@lwj-desktop:~/Desktop/C/myping$ sudo ./ping localhost
Password:
ping localhost(127.0.0.1) 8(36) bytes of data
36(56) bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.061ms
36(56) bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.051ms
36(56) bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.039ms
36(56) bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.051ms
36(56) bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.050ms
36(56) bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.052ms
36(56) bytes from 127.0.0.1: icmp_seq=6 ttl=64 time=0.051ms
36(56) bytes from 127.0.0.1: icmp_seq=7 ttl=64 time=0.053ms
[2]+ Stopped sudo ./ping localhost
lwj@lwj-desktop:~/Desktop/C/myping$ sudo ./ping 10.3.2.206
ping 10.3.2.206(10.3.2.206) 8(36) bytes of data
36(56) bytes from 10.3.2.206: icmp_seq=0 ttl=64 time=0.233ms
36(56) bytes from 10.3.2.206: icmp_seq=1 ttl=64 time=0.063ms
36(56) bytes from 10.3.2.206: icmp_seq=2 ttl=64 time=0.044ms
36(56) bytes from 10.3.2.206: icmp_seq=3 ttl=64 time=0.054ms
36(56) bytes from 10.3.2.206: icmp_seq=4 ttl=64 time=0.044ms
36(56) bytes from 10.3.2.206: icmp_seq=5 ttl=64 time=0.052ms
36(56) bytes from 10.3.2.206: icmp_seq=6 ttl=64 time=0.058ms
36(56) bytes from 10.3.2.206: icmp_seq=7 ttl=64 time=0.055ms
36(56) bytes from 10.3.2.206: icmp_seq=8 ttl=64 time=0.066ms
36(56) bytes from 10.3.2.206: icmp_seq=9 ttl=64 time=0.053ms
36(56) bytes from 10.3.2.206: icmp_seq=10 ttl=64 time=0.053ms
36(56) bytes from 10.3.2.206: icmp_seq=11 ttl=64 time=0.052ms
[3]+ Stopped sudo ./ping 10.3.2.206
lwj@lwj-desktop:~/Desktop/C/myping$ sudo ./ping 10.3.2.205
ping 10.3.2.205(10.3.2.205) 8(36) bytes of data
茶杯头甜蜜终章dlc 官方手机版v1.0.0.3
下载火柴人传说暗影格斗内置菜单 最新版v3.0.1
下载荒野乱斗测试服 安卓版v61.10.3
下载荒野乱斗彩虹服 安卓版v61.10.3
下载寒霜启示录 安卓版v1.25.10
寒霜启示录是一款生存模拟游戏,不少玩家可能对于末日都有着自己
末日城堡免广告版 安卓最新版v0.7.1
末日城堡免广告版是一款非常好玩的模拟经营类游戏,内部可以不看
甜蜜人生模拟器 最新版v1.4.5
甜蜜人生模拟器是一款非常好玩的模拟恋爱手游,玩家在这里能够对
武器锻造师内置功能菜单 v10.4
武器锻造师内置菜单版是游戏的破解版本,在该版本中为玩家提供了
开放空间overfield 安卓版v1.0.5
开放空间Overfield是一款箱庭养成经营手游,让你在广阔