天天看點

c語言ping指令windows,(zt)用C語言實作Ping程式功能Windows系統 -電腦資料

struct icmp

{

u_int8_t icmp_type; 

u_int8_t icmp_code; 

u_int16_t icmp_cksum; 

union

{

u_char ih_pptr; 

struct in_addr ih_gwaddr; 

struct ih_idseq 

{

u_int16_t icd_id;

u_int16_t icd_seq;

} ih_idseq;

u_int32_t ih_void;

struct ih_pmtu

{

u_int16_t ipm_void;

u_int16_t ipm_nextmtu;

} ih_pmtu;

struct ih_rtradv

{

u_int8_t irt_num_addrs;

u_int8_t irt_wpa;

u_int16_t irt_lifetime;

} ih_rtradv;

} icmp_hun;

#define icmp_pptr icmp_hun.ih_pptr

#define icmp_gwaddr icmp_hun.ih_gwaddr

#define icmp_id icmp_hun.ih_idseq.icd_id

#define icmp_seq icmp_hun.ih_idseq.icd_seq

#define icmp_void icmp_hun.ih_void

#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void

#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu

#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs

#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa

#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime

union

{

struct

{

u_int32_t its_otime;

u_int32_t its_rtime;

u_int32_t its_ttime;

} id_ts;

struct

{

struct ip idi_ip;

} id_ip;

struct icmp_ra_addr id_radv;

u_int32_t id_mask;

u_int8_t id_data[1];

} icmp_dun;

#define icmp_otime icmp_dun.id_ts.its_otime

#define icmp_rtime icmp_dun.id_ts.its_rtime

#define icmp_ttime icmp_dun.id_ts.its_ttime

#define icmp_ip icmp_dun.id_ip.idi_ip

#define icmp_radv icmp_dun.id_radv

#define icmp_mask icmp_dun.id_mask

#define icmp_data icmp_dun.id_data

};

使用宏定義令表達更簡潔,其中ICMP報頭為8位元組,資料報長度最大為64K位元組。

校驗和算法――這一算法稱為網際校驗和算法,把被校驗的資料16位進行累加,然後取反碼,若資料位元組長度為奇數,則資料尾部補一個位元組的0以湊成偶數。此算法适用于IPv4、ICMPv4、IGMPV4、ICMPv6、UDP和TCP校驗和,更詳細的資訊請參考RFC1071,校驗和字段為上述ICMP資料結構的icmp_cksum變量。

辨別符――用于唯一辨別ICMP封包, 為上述ICMP資料結構的icmp_id宏所指的變量。

順序号――ping指令的icmp_seq便由這裡讀出,代表ICMP封包的發送順序,為上述ICMP資料結構的icmp_seq宏所指的變量。

ICMP資料報

Ping指令中需要顯示的資訊,包括icmp_seq和ttl都已有實作的辦法,但還缺rtt往返時間。為了實作這一功能,可利用ICMP資料報攜帶一個時間戳。使用以下函數生成時間戳:

#include

int gettimeofday(struct timeval *tp,void *tzp)

其中timeval結構如下:

struct timeval{

long tv_sec;

long tv_usec;

}

其中tv_sec為秒數,tv_usec微秒數。在發送和接收封包時由gettimeofday分别生成兩個timeval結構,兩者之差即為往返時間,即ICMP封包發送與接收的時間差,而timeval結構由ICMP資料報攜帶,tzp指針表示時區,一般都不使用,賦NULL值。

資料統計

系統自帶的ping指令當它接送完所有ICMP封包後,會對所有發送和所有接收的ICMP封包進行統計,進而計算ICMP封包丢失的比率。為達此目的,定義兩個全局變量:接收計數器和發送計數器,用于記錄ICMP封包接受和發送數目。丢失數目=發送總數-接收總數,丢失比率=丢失數目/發送總數。

現給出模拟Ping程式功能的代碼如下:

#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 3

char 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;

while(nleft>1)

{ sum+=*w++;

nleft-=2;

}