将pingip用c语言代码实现
时间: 2023-10-09 21:14:17 浏览: 38
下面是一个使用C语言实现ping命令的示例代码,它会向目标IP地址发送ICMP报文,并等待接收到响应报文:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/time.h>
#include <unistd.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;
void send_packet();
void recv_packet();
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 timezone tz;
unsigned long inaddr = 0;
int size = 50 * 1024;
pid = getpid();
memset(sendpacket, 0x7e, sizeof(sendpacket));
if (argc < 2) {
printf("usage: %s hostname/IP address\n", argv[0]);
return 1;
}
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
perror("socket error");
return 1;
}
setuid(getuid());
setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
bzero(&dest_addr, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
if (inaddr = inet_addr(argv[1]) == INADDR_NONE) {
if ((host = gethostbyname(argv[1])) == NULL) {
perror("gethostbyname error");
return 1;
}
memcpy((char*)&dest_addr.sin_addr, host->h_addr, host->h_length);
} else {
dest_addr.sin_addr.s_addr = inaddr;
}
printf("PING %s (%s): %d bytes data in ICMP packets.\n", argv[1], inet_ntoa(dest_addr.sin_addr), datalen);
send_packet();
signal(SIGALRM, statistics);
gettimeofday(&tv, &tz);
while (nsend < MAX_NO_PACKETS) {
recv_packet();
nsend++;
send_packet();
alarm(MAX_WAIT_TIME);
}
return 0;
}
void send_packet()
{
struct icmp *icmp;
int len;
icmp = (struct icmp*)sendpacket;
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
icmp->icmp_cksum = 0;
icmp->icmp_seq = nsend;
icmp->icmp_id = pid;
len = datalen + 8;
icmp->icmp_cksum = cal_chksum((unsigned short*)icmp, len);
sendto(sockfd, sendpacket, len, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));
}
void recv_packet()
{
int n;
socklen_t fromlen;
extern int errno;
struct timeval tvrecv;
struct ip *ip;
struct icmp *icmp;
signal(SIGALRM, statistics);
fromlen = sizeof(dest_addr);
if ((n = recvfrom(sockfd, recvpacket, sizeof(recvpacket), 0, (struct sockaddr*)&dest_addr, &fromlen)) < 0) {
if (errno == EINTR) {
return;
}
perror("recvfrom error");
return;
}
gettimeofday(&tvrecv, NULL);
ip = (struct ip*)recvpacket;
icmp = (struct icmp*)(recvpacket + (ip->ip_hl << 2));
nreceived++;
printf("%d bytes from %s: icmp_seq=%u ttl=%d time=%.2f ms\n", n, inet_ntoa(dest_addr.sin_addr), icmp->icmp_seq, ip->ip_ttl, (tvrecv.tv_sec - tvrecv.tv_sec) * 1000.0 + (tvrecv.tv_usec - tvrecv.tv_usec) / 1000.0);
}
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;
}
void statistics(int signo)
{
printf("%d packets transmitted, %d received, %%%d lost\n", nsend, nreceived, (nsend - nreceived) / nsend * 100);
close(sockfd);
exit(1);
}
```
需要注意的是,由于ping命令需要使用原始套接字进行网络通信,因此需要root权限运行该程序。可以使用setuid(getuid())函数将程序的权限设置为当前用户,以避免安全问题。