linux下ping程序实现
这里使用socket实现ping程序的所有功能。
可以借此了解以下icmp协议的设计细节和注意事项。
支持以下功能:
- 支持ping域名和ip地址
- 支持自定义发包个数
- 支持自定义ttl
- 支持超时设定
使用方法:
//打印帮助
Linux_ping -h
//参数设定
Linux_ping -c 10 -t 100 -w 100 ip/域名
来介绍下功能关键点:
创建ICMP套接字
//RAW套接字,需要root权限
g_sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
TTL设定
TTL(Time To Live)
该字段指定IP包被路由器丢弃之前允许通过的最大网段数量
如果设置的ttl过小,那么就就会收不到回包
UINT32 ttl = TTL;
setsockopt(g_sockfd, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl));
域名到IP的转换
//是主机名
if (inet_addr(szHost) == INADDR_NONE)
{
host = gethostbyname(szHost);
if(host==NULL)
{
perror("获取主机名错误");
return -1;
}
//成功的话,ip地址存在host里面
}
字符串到IP的转换
dest_addr.sin_addr.s_addr = inet_addr(szHost);
printf("IP:%s\n", inet_ntoa(g_dest_addr.sin_addr));
网络字节序
网络字节序是大端
X86体系是小端字节序,一般都需要自行转换字节序
以下常用函数用于字节序转换:
//主机序->网络序
htonl()
//网络序->主机序
ntohl()
自定义ICMP报头
//类型
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
//校验码,必须默认置0
icmp->icmp_cksum = 0;
icmp->icmp_seq = pack_no;
icmp->icmp_id=pid;
//头部8个字节
packsize = 8 + g_datalen;
icmp->icmp_cksum=cal_chksum((unsigned short *)icmp, packsize);
使用alarm()设置超时
alarm()主要功能: 设置信号传送闹钟
即用来设置信号SIGALRM在经过参数seconds秒数后发送给目前的进程
果在seconds秒内再次调用了alarm函数则后面定时器的设置将覆盖前面的设置
主要逻辑:
signal(SIGALRM,Statistic);
while(g_nRecv < g_nNeedSend)
{
alarm(g_nWait);
recvfrom(g_sockfd, g_RecvPacket, sizeof(g_RecvPacket), 0, (struct sockaddr *)&g_from,&nfromlen);
}
这里使用了阻塞recvfrom(),如果接收超时会触发我们设置的signal函数
运行结果:
发表评论
要发表评论,您必须先登录。