个人简单ping程序学习及实现

 


1.什么是ping程序

 PING程序是测试网络连接,返回网络信息的一个工具,能返回往返时间、途径路由器数量等参数

 

2.PING使用的协议

PING用ICMP报文协议

3.什么是原始套接字

原始套接字能直接对ip数据包进行操作,能支持icmp,igmp等协议,还可以在开启IP_HDRINCL套接字选项下对IP首部进行构造

在创建套接字是套接字类型指定SOCK_RAW即可创建原始套接字。

4.PING程序的网络模型

PING程序网络模型想过当于客户/服务器网络模型,ping程序相当于客户程序,不停发送请求,循环等待接受回复消息,然后处理输出到客户端,

ping的地址相当于服务器,接受消息发回icmp应答报文。

5.PING程序运行流程

1.创建原始套接字

2.设置时钟信号处理程序,每次接受到信号就发送ICMP报文,时钟程序每过1秒,发出SIGALARM信号

3.等待接受ICMP应答报文,处理报文,输出TTL,RTT等信息

6.总结思考

是否可以利用其他协议实现PING程序,一些服务器对ping请求直接忽略,可否利用TCP/UDP协议实现类似功能

参考程序hping。

附上linux下源码

 

#include "unp.h"
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>

#define BUFSIZE 1500
char    *host;
pid_t    pid;
int	sockfd;
int	nsent;
int 	datalen=56;
char	sendbuf[BUFSIZE];
struct sockaddr  *sasend;
struct addrinfo *ai;

uint16_t
in_cksum(uint16_t *add, int len)
{
	int	nleft = len;
	uint32_t sum = 0;
	uint16_t *w = add;
	uint16_t answer =  0;

	while (nleft > 1){
	sum += *w++;
	nleft -= 2;	
	}
	if ( nleft == 1){
 	*(unsigned char *)(&answer) = *(unsigned char *)w;
	sum+=answer;
	}
	sum = (sum >> 16) + (sum & 0xffff);
	sum += (sum >> 16);
	answer = ~sum;
	return (answer);
	 err_quit("cksum");
}



void
send_a()
{
	int	m;
	int	len;
	struct	icmp *icmp;

	icmp = (struct icmp *) sendbuf;
	icmp->icmp_type = ICMP_ECHO;
	icmp->icmp_code = 0;
	icmp->icmp_id = pid;
	icmp->icmp_seq = nsent++;
	memset(icmp->icmp_data, 0xa5, datalen);
	gettimeofday((struct timeval *) icmp->icmp_data, NULL);

	len = 8 + datalen;
	icmp->icmp_cksum = 0;
	icmp->icmp_cksum = in_cksum((u_short *) icmp, len);
	
	if((m=sendto(sockfd, sendbuf, len, 0, ai->ai_addr, ai->ai_addrlen))== -1)
		err_quit("sendto error");
}
	
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;
}


void
proc(char *ptr, ssize_t len, struct msghdr *msg, struct timeval *tvrecv)
{
	int	hlenl, icmplen;
	double  rtt;
	struct ip *ip;
	struct icmp *icmp;
	struct timeval *tvsend;
	
	ip = (struct ip *) ptr;
	hlenl = (ip->ip_hl << 2);
	if (ip->ip_p != IPPROTO_ICMP)
		return;
	icmp = (struct icmp *)(ptr + hlenl);
	if ( (icmplen =len -hlenl) < 8)	
 		return ;
	if (icmp->icmp_type == ICMP_ECHOREPLY)	{
		if (icmp->icmp_id != pid)
			return;
		if(icmplen <  16)
			return;
		
		tvsend = (struct timeval *) icmp->icmp_data;
		tv_sub(tvrecv, tvsend);
		rtt = tvrecv->tv_sec * 1000.0 + tvrecv->tv_usec/1000.0;
		
		printf("%d bytes from %s: seq=%u,ttl=%d, rtt=%.3f ms\n",
			  icmplen, host,icmp->icmp_seq, ip->ip_ttl,rtt);
		}
	
}


void
sig_alrm(int signo)
{
	send_a();
	alarm(1);
	return;
}

void
readloop()
{
	int size;
	char recvbuf[BUFSIZE];
	char controlbuf[BUFSIZE];
	struct iovec iov;
	struct msghdr msg;
	struct timeval  tval;
	ssize_t nn;


	sockfd = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
	setuid(getuid());
		
	size=60 * 1024;
	setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size,sizeof(size));
	
	sig_alrm(SIGALRM);

	iov.iov_base = recvbuf;
	iov.iov_len = sizeof(recvbuf);
	msg.msg_name = calloc(1,ai->ai_addrlen);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = controlbuf;
	for ( ; ; ){
		msg.msg_namelen = ai->ai_addrlen;
		msg.msg_controllen = sizeof(controlbuf);
		nn = recvmsg (sockfd, &msg, 0);
		if (nn < 0){
		   if (errno == EINTR)
			continue;
		   else
			err_sys("recvmsg error");
			 }
		
		gettimeofday(&tval, NULL);
		proc(recvbuf, nn, &msg, &tval);

	}
	
}

int
main(int argc, char **argv)
{
	ssize_t	n;
	struct  addrinfo *res;
	if (argc!=2) 
		err_quit("argument not enougth");
	
	host = argv[1];
	pid = getpid() & 0xffff;
	
	signal(SIGALRM,sig_alrm);
	
	if (n = getaddrinfo(host,NULL,0,&res) != 0)
		return 0;
	ai = host_serv(host,NULL,0,0);
	readloop();

	exit(0);
}

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值