linux ping源码
时间: 2023-10-03 10:09:58 浏览: 66
ping源码分析-Linux网络编程
Linux的ping命令的源代码可以在网络上进行查找和下载。以下是ping命令的基本源代码:
```
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/time.h>
#include <errno.h>
#include <signal.h>
#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;
void statistics(int signo);
unsigned short cal_chksum(unsigned short *addr, int len);
int main(int argc, char *argv[])
{
struct hostent *host;
struct timeval tv;
struct timeval start, end;
struct timezone tz;
int n;
unsigned char ttl = 64, loop = 1;
bzero(&dest_addr, sizeof(dest_addr));
if(argc<2)
{
printf("usage:%s hostname/IP address\n", argv[0]);
exit(1);
}
if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
{
perror("socket");
exit(1);
}
pid = getpid();
setsockopt(sockfd, SOL_IP, IP_TTL, &ttl, sizeof(ttl));
setsockopt(sockfd, SOL_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
dest_addr.sin_family = AF_INET;
if(inet_addr(argv[1]) == INADDR_NONE)
{
if((host = gethostbyname(argv[1])) == NULL)
{
perror("gethostbyname error");
exit(1);
}
memcpy((char *)&dest_addr.sin_addr, host->h_addr, host->h_length);
}
else
dest_addr.sin_addr.s_addr = inet_addr(argv[1]);
printf("PING %s (%s): %d data bytes\n", argv[1], inet_ntoa(dest_addr.sin_addr), datalen);
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
while(nsend < MAX_NO_PACKETS)
{
nsend++;
gettimeofday(&start, &tz);
memset(sendpacket, 0, sizeof(sendpacket));
memset(recvpacket, 0, sizeof(recvpacket));
struct icmp *icmp;
icmp = (struct icmp*)sendpacket;
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
icmp->icmp_id = pid;
icmp->icmp_seq = nsend;
memset(icmp->icmp_data, '1', datalen);
icmp->icmp_cksum = cal_chksum((unsigned short *)icmp, datalen + 8);
if(sendto(sockfd, sendpacket, sizeof(sendpacket), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < 0)
{
perror("sendto error");
continue;
}
if(recvfrom(sockfd, recvpacket, sizeof(recvpacket), 0, (struct sockaddr *)&from, &n) < 0)
{
perror("recvfrom error");
continue;
}
gettimeofday(&end, &tz);
struct ip *ip;
struct icmp *icmp_back;
double rtt;
int len = 0;
ip = (struct ip*)recvpacket;
len = ip->ip_hl * 4;
icmp_back = (struct icmp*)(recvpacket + len);
if((icmp_back->icmp_type == ICMP_ECHOREPLY) && (icmp_back->icmp_id == pid))
{
nreceived++;
printf("%d bytes from %s: icmp_seq=%u ttl=%d time=%.2f ms\n",
datalen, inet_ntoa(from.sin_addr), icmp_back->icmp_seq, ip->ip_ttl, rtt);
rtt = 1000 * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1000;
}
else
printf("receive packet error!\n");
sleep(1);
}
statistics(SIGALRM);
return 0;
}
void statistics(int signo)
{
printf("\n%d packets transmitted, %d received, %%%d lost\n", nsend, nreceived, (nsend - nreceived) / nsend * 100);
}
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;
}
if(nleft == 1)
{
*(unsigned char *)(&answer) = *(unsigned char *)w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
answer = ~sum;
return answer;
}
```
这段代码实现了ping命令的基本功能,包括构建ICMP数据包、发送和接收数据包、计算RTT等。需要注意的是,此代码只作为示例,实际使用时可能需要根据具体需求进行修改和优化。
阅读全文