原始套接字之PING(2)

主函数:

/*ping.c*/ 
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>
#include <signal.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h> /*bzero*/
#include <netdb.h>
#include <pthread.h>
/*保存已经发送包的状态值*/
typedef struct pingm_pakcet{
	struct timeval tv_begin;	/*发送的时间*/
	struct timeval tv_end;		/*接收到的时间*/
	short seq;					/*序列号*/
	int flag;		/*1,表示已经发送但没有接收到回应包0,表示接收到回应包*/
}pingm_pakcet;
static pingm_pakcet pingpacket[128];
static pingm_pakcet *icmp_findpacket(int seq);
static unsigned short icmp_cksum(unsigned char *data,  int len);
static struct timeval icmp_tvsub(struct timeval end,struct timeval begin);
static void icmp_statistics(void);
static void icmp_pack(struct icmp *icmph, int seq, struct timeval *tv, int length );
static int icmp_unpack(char *buf,int len);
static void *icmp_recv(void *argv);
static void *icmp_send(void *argv);
static void icmp_sigint(int signo);
static void icmp_usage();
#define K 1024
#define BUFFERSIZE 72					/*发送缓冲区大小*/
static char send_buff[BUFFERSIZE];
static char recv_buff[2*K];	/*为防止接收溢出,接收缓冲区设置大一些*/
static struct sockaddr_in dest;		/*目的地址*/
static int rawsock = 0;					/*发送和接收线程需要的socket描述符*/
static pid_t pid=0;						/*进程PID*/
static int alive = 0;					/*是否接收到退出信号*/
static short packet_send = 0;			/*已经发送的数据包有多少*/
static short packet_recv = 0;			/*已经接收的数据包有多少*/
static char dest_str[80];				/*目的主机字符串*/
static struct timeval tv_begin, tv_end,tv_interval;
/*本程序开始发送、结束和时间间隔*/
static void icmp_usage()
{
	/*ping加IP地址或者域名*/
	printf("ping aaa.bbb.ccc.ddd\n");
}
/*主程序*/
int main(int argc, char *argv[])
{
	struct hostent * host = NULL;
	struct protoent *protocol = NULL;
	char protoname[]= "icmp";
	unsigned long inaddr = 1;
	int size = 128*K;
	/*参数是否数量正确*/
	if(argc < 2)
	{
		icmp_usage();
		return -1;
	}
	/*获取协议类型ICMP*/
	protocol = getprotobyname(protoname);
	if (protocol == NULL)
	{
		perror("getprotobyname()");
		return -1;
	}
	/*复制目的地址字符串*/
	memcpy(dest_str,  argv[1], strlen(argv[1])+1);
	memset(pingpacket, 0, sizeof(pingm_pakcet) * 128);
	/*socket初始化*/
	rawsock = socket(AF_INET, SOCK_RAW,  protocol->p_proto);
	if(rawsock < 0)
	{
		perror("socket");
		return -1;
	}
	/*为了与其他进程的ping程序区别,加入pid*/
	pid = getuid();
	/*增大接收缓冲区,防止接收的包被覆盖*/
	setsockopt(rawsock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
	bzero(&dest, sizeof(dest));
	/*获取目的地址的IP地址*/
	dest.sin_family = AF_INET;
	
	/*输入的目的地址为字符串IP地址*/
	inaddr = inet_addr(argv[1]);
	if(inaddr == INADDR_NONE)
	{
		/*输入的是DNS地址*/
		host = gethostbyname(argv[1]);
		if(host == NULL)
		{
			perror("gethostbyname");
			return -1;
		}
		/*将地址复制到dest中*/
		memcpy((char *)&dest.sin_addr, host->h_addr, host->h_length);
	}
	else		/*为IP地址字符串*/
	{
		memcpy((char*)&dest.sin_addr, &inaddr, sizeof(inaddr));
	}
	/*打印提示*/
	inaddr = dest.sin_addr.s_addr;
	printf("PING %s (%ld.%ld.%ld.%ld) 56(84) bytes of data.\n", 
		dest_str, 
		(inaddr&0x000000FF)>>0,
		(inaddr&0x0000FF00)>>8,
		(inaddr&0x00FF0000)>>16,
		(inaddr&0xFF000000)>>24);
	/*截取信号SIGINT,将icmp_sigint挂接上*/
	signal(SIGINT, icmp_sigint);
	alive = 1;						/*初始化为可运行*/
	pthread_t send_id, recv_id;		/*建立两个线程,用于发送和接收*/
	int err = 0;
	err = pthread_create(&send_id, NULL, icmp_send, NULL);		/*发送*/
	if(err < 0)
	{
		return -1;
	}
	err = pthread_create(&recv_id, NULL, icmp_recv, NULL);		/*接收*/
	if(err < 0)
	{
		return -1;
	}
	
	/*等待线程结束*/
	pthread_join(send_id, NULL);
	pthread_join(recv_id, NULL);
	/*清理并打印统计结果*/
	close(rawsock);
	icmp_statistics();
	return 0;	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会飞的幸运儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值