ping的原理很简单,根据ICMP协议的特性就可以做出来。linux的头文件中包含了相应的信息。这里我就不多数了,相关的协议知识,请看相关文档。下面是我自己写的简单ping代码。
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#define DATALEN 40
#define MAXBUFLEN 1024
#define DEFAULTPORT 8888
unsigned short in_chksum (u_short *addr, int len)
{
register int nleft = len;
register int sum = 0;
u_short answer = 0;
while (nleft > 1)
{
sum += *addr++;
nleft -= 2;
}
if (nleft == 1)
{
*(u_char *)(&answer) = *(u_char *)addr;
sum += answer;
}
sum = (sum >> 16) + (sum + 0xffff);
sum += (sum >> 16);
answer = ~sum;
return(answer);
}
int main(int argc, char** argv)
{
struct sockaddr_in address,fromaddress;
struct in_addr inaddr;
struct hostent * host;
int sock ;
char host_name[256],*ifbuf;
char buf[MAXBUFLEN];
int i, len,fromlen,passtime;
int timeout = 1000 ;
struct icmp *icmpdata;
struct timeval newtime,sendtime;
gethostname(host_name,MAXBUFLEN);
host = gethostbyname(host_name);
if (host)
{
i=0;
while (host->h_addr_list[i])
{
memcpy(&inaddr, host->h_addr_list[i],sizeof(address.sin_addr));
printf("local ip: %s/n",inet_ntoa(inaddr));
i++;
}
}
if (argc != 3)
{
fprintf(stderr, "%s destip [timeout(ms)]/n",argv[0]);
fprintf(stderr, "only 1 or 2 argument is supported/n");
return 1;
}
host = gethostbyname(argv[1]);
if (argc > 2)
{
timeout = atoi(argv[2]);
}
if (timeout<10)
{
timeout=10;
}
if (!host)
{
printf("error looking up host %s/n",argv[1]);
exit(1);
}
if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
{
perror("socket");
exit(0);
}
if(fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
{
perror("ioctl FIONBIO");
}
if (setsockopt(sock, SOL_SOCKET,SO_SNDBUF,(char*)&timeout,sizeof(timeout))<0)
{
perror("setsockopt SO_SNDBUF");
}
if (setsockopt(sock, SOL_SOCKET,SO_RCVBUF,(char*)&timeout,sizeof(timeout))<0)
{
perror("setsockopt SO_RCVBUF");
}
address.sin_family = AF_INET;
memcpy(&address.sin_addr, host->h_addr_list[0],sizeof(address.sin_addr));
icmpdata = (struct icmp*)buf;
memset(buf,0,sizeof(buf));
icmpdata->icmp_type = ICMP_ECHO;
icmpdata->icmp_code = 0;
icmpdata->icmp_id = 0;
icmpdata->icmp_seq = 0;
gettimeofday((struct timeval*)&sendtime,NULL);
len = 8+DATALEN;
icmpdata->icmp_cksum = 0;
icmpdata->icmp_cksum =in_chksum((unsigned short *)icmpdata,len);
sendto(sock,buf,len,0,(struct sockaddr *) &address,sizeof(struct sockaddr_in));
while (1)
{
len = recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr *)&fromaddress,&fromlen);
gettimeofday((struct timeval*)&newtime,NULL);
passtime = ((newtime.tv_sec-sendtime.tv_sec)*1000+(newtime.tv_usec-sendtime.tv_usec)/1000);
if (len<1)
{
if (passtime>timeout)
{
printf("Time out %d msec/n",passtime);
break;
}
else
{
usleep(10000);
}
}
else
{
printf("echo back %d bytes in %d msec/n",len,passtime);
for (i=0 ; i<len; i++)
{
printf("%02X ", buf[i]&0xFF);
if ((i+1)%16 ==0) printf("/n");
}
printf("/n");
break;
}
}
close(sock);
return 0;
}
这段代码可以检测网络。
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#define DATALEN 40
#define MAXBUFLEN 1024
#define DEFAULTPORT 8888
unsigned short in_chksum (u_short *addr, int len)
{
register int nleft = len;
register int sum = 0;
u_short answer = 0;
while (nleft > 1)
{
sum += *addr++;
nleft -= 2;
}
if (nleft == 1)
{
*(u_char *)(&answer) = *(u_char *)addr;
sum += answer;
}
sum = (sum >> 16) + (sum + 0xffff);
sum += (sum >> 16);
answer = ~sum;
return(answer);
}
int main(int argc, char** argv)
{
struct sockaddr_in address,fromaddress;
struct in_addr inaddr;
struct hostent * host;
int sock ;
char host_name[256],*ifbuf;
char buf[MAXBUFLEN];
int i, len,fromlen,passtime;
int timeout = 1000 ;
struct icmp *icmpdata;
struct timeval newtime,sendtime;
gethostname(host_name,MAXBUFLEN);
host = gethostbyname(host_name);
if (host)
{
i=0;
while (host->h_addr_list[i])
{
memcpy(&inaddr, host->h_addr_list[i],sizeof(address.sin_addr));
printf("local ip: %s/n",inet_ntoa(inaddr));
i++;
}
}
if (argc != 3)
{
fprintf(stderr, "%s destip [timeout(ms)]/n",argv[0]);
fprintf(stderr, "only 1 or 2 argument is supported/n");
return 1;
}
host = gethostbyname(argv[1]);
if (argc > 2)
{
timeout = atoi(argv[2]);
}
if (timeout<10)
{
timeout=10;
}
if (!host)
{
printf("error looking up host %s/n",argv[1]);
exit(1);
}
if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
{
perror("socket");
exit(0);
}
if(fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
{
perror("ioctl FIONBIO");
}
if (setsockopt(sock, SOL_SOCKET,SO_SNDBUF,(char*)&timeout,sizeof(timeout))<0)
{
perror("setsockopt SO_SNDBUF");
}
if (setsockopt(sock, SOL_SOCKET,SO_RCVBUF,(char*)&timeout,sizeof(timeout))<0)
{
perror("setsockopt SO_RCVBUF");
}
address.sin_family = AF_INET;
memcpy(&address.sin_addr, host->h_addr_list[0],sizeof(address.sin_addr));
icmpdata = (struct icmp*)buf;
memset(buf,0,sizeof(buf));
icmpdata->icmp_type = ICMP_ECHO;
icmpdata->icmp_code = 0;
icmpdata->icmp_id = 0;
icmpdata->icmp_seq = 0;
gettimeofday((struct timeval*)&sendtime,NULL);
len = 8+DATALEN;
icmpdata->icmp_cksum = 0;
icmpdata->icmp_cksum =in_chksum((unsigned short *)icmpdata,len);
sendto(sock,buf,len,0,(struct sockaddr *) &address,sizeof(struct sockaddr_in));
while (1)
{
len = recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr *)&fromaddress,&fromlen);
gettimeofday((struct timeval*)&newtime,NULL);
passtime = ((newtime.tv_sec-sendtime.tv_sec)*1000+(newtime.tv_usec-sendtime.tv_usec)/1000);
if (len<1)
{
if (passtime>timeout)
{
printf("Time out %d msec/n",passtime);
break;
}
else
{
usleep(10000);
}
}
else
{
printf("echo back %d bytes in %d msec/n",len,passtime);
for (i=0 ; i<len; i++)
{
printf("%02X ", buf[i]&0xFF);
if ((i+1)%16 ==0) printf("/n");
}
printf("/n");
break;
}
}
close(sock);
return 0;
}
这段代码可以检测网络。