1 Star 0 Fork 0

zconf/ping

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
ping.c 5.61 KB
一键复制 编辑 原始数据 按行查看 历史
zconf 提交于 2019-05-06 10:27 . done
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <memory.h>
#include <netinet/ip_icmp.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PKG_SIZE 1024
char package[PKG_SIZE];
char addrBuf[1024]; /* 存储ip字符串 */
int packageSize=64;
int packageSent=0;
int packageRecv=0;
int sockfd;
int pingTimes=3;
struct timeval startTime;
struct timeval endTime;
struct sockaddr_in destaddr;
char* destaddrStr;
char* hostname;
unsigned short
checksum(unsigned short *addr,int len)
{ int nleft=len;
int sum=0;
unsigned short *w=addr;
unsigned short answer=0;
/*把ICMP报头二进制数据以2字节为单位累加起来*/
while(nleft>1)
{ sum+=*w++;
nleft-=2;
}
/*若ICMP报头为奇数个字节,会剩下最后一字节。把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加*/
if( nleft==1)
{ *(unsigned char *)(&answer)=*(unsigned char *)w;
sum+=answer;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=~sum;
return answer;
}
/**
* 初始化icmp报文
*/
int
pack(int pack_no, char* buf) {
struct icmphdr* icmphdr = (struct icmphdr*) buf;
bzero(buf, packageSize);
icmphdr->type = ICMP_ECHO;
icmphdr->code = 0;
icmphdr->checksum = 0; // 稍后计算
icmphdr->un.echo.id = htons(getpid());
icmphdr->un.echo.sequence = htons(pack_no);
char* data = buf + sizeof(*icmphdr);
// 时间戳写入到包中
struct timeval* tv = (struct timeval*)data;
gettimeofday(tv, NULL);
// 计算校验和
icmphdr->checksum = checksum((unsigned short*)icmphdr, packageSize);
return packageSize;
}
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;
}
int
unpack(char* buf) {
// 这里需要注意, buf指向的是ip报文
unsigned short chksum;
struct ip* ip = (struct ip*)buf;
struct icmp* icmp = (struct icmp*)(buf+sizeof(*ip));
//checksum
chksum = checksum((unsigned short*)icmp, packageSize);
if (chksum) {
printf("expected chksum: %x\n", chksum);
printf("actual chksum: %x\n", icmp->icmp_cksum);
return -1;
}
// 计算时间
struct timeval tv;
gettimeofday(&tv, NULL);
struct timeval* recvtv = (struct timeval*)icmp->icmp_data;
tv_sub(&tv, recvtv);
int timedelta = tv.tv_sec*1000 + tv.tv_usec/1000;
inet_ntop(AF_INET, &destaddr.sin_addr, addrBuf, sizeof (struct sockaddr));
printf("%d bytes from %s: icmp_seq=%d ttl=%d time=%d ms\n",
packageSize,
inet_ntoa(ip->ip_src), htons(icmp->icmp_seq),
ip->ip_ttl, timedelta);
return 0;
}
void
ping() {
gettimeofday(&startTime, NULL);
for (int i = 0 ; i < pingTimes ; i++) {
bzero(package, packageSize);
pack(i, package);
if (sendto(sockfd, package, packageSize, 0,
(struct sockaddr*)&destaddr,
sizeof(destaddr)) < 0) {
perror("sendto");
exit(-1);
}
packageSent++;
socklen_t len;
if (recvfrom(sockfd, package, packageSize, 0,
(struct sockaddr*)&destaddr, &len) > 0) {
if (unpack(package) == 0) {
packageRecv++;
} else {
printf("wrong package\n");
}
} else {
perror("recvfrom");
}
gettimeofday(&endTime, NULL);
sleep(1);
// 延时, 每秒发送一次
}
}
void
summary() {
tv_sub(&endTime, &startTime);
long totalTime = endTime.tv_sec*1000 + endTime.tv_usec/1000;
printf("\n--- %s ping statictics ---\n", hostname);
printf("%d packets transmitted, %d received %d%% packet loss, time %ldms",
packageSent, packageRecv, 100*(packageRecv-packageSent)/packageSent,
totalTime);
}
void
intAndTriggerSummary(int signo) {
summary();
exit(0);
}
void
usage(char* name) {
printf("Usage: %s <host> [-c count]\n", name);
}
int
main(int argc, char** argv) {
signal(SIGINT, intAndTriggerSummary);
if (argc < 2) {
printf("Usage: %s <host>\n", argv[0]);
exit(-1);
}
if (argc == 2) {
pingTimes = INT_MAX;
} else if (argc == 4 && strcmp(argv[2], "-c") == 0) {
pingTimes = strtol(argv[3], NULL, 10);
if (errno || pingTimes <= 0) {
usage(argv[0]);
exit(-1);
}
} else {
usage(argv[0]);
exit(-1);
}
struct protoent* protocol;
// 1. 解析参数
hostname = argv[1];
struct hostent* host = NULL;
if ((host = gethostbyname(hostname)) == NULL) {
perror("gethostbyname");
exit(-1);
}
struct in_addr* address = (struct in_addr*)host->h_addr_list[0];
destaddr.sin_addr = *address;
destaddrStr = inet_ntoa(*address);
bzero(&destaddr, sizeof(destaddr));
destaddr.sin_addr = *address;
destaddr.sin_family = AF_INET;
if ((protocol = getprotobyname("icmp")) == NULL) {
perror("getprotobyname");
exit(-1);
}
// 2. 创建套接字
if ((sockfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) < 0) {
perror("socket");
exit(-1);
}
setuid(getuid());
printf("PING %s (%s)\n", hostname, destaddrStr);
// 3. 发送数据
// 开始ping
ping();
// 4. 统计数据
summary();
return 0;
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/zconf/ping.git
[email protected]:zconf/ping.git
zconf
ping
ping
master

搜索帮助