C语言实现ping功能(Linux & Mac OS系统下)有注释
2017-12-21 17:29
603 查看
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>//socket()
#include <stdlib.h>
#include <unistd.h>//getpid
#include <arpa/inet.h>//IPPROTO_ICMP
#include <sys/time.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>//ICMP_ECHO
float timediff(struct timeval * recTime,struct timeval * nowTime){
struct timeval sub = *nowTime;
if ((sub.tv_usec -= recTime->tv_usec) <
0)
{
--(sub.tv_sec);
sub.tv_usec += 1000000;
}
sub.tv_sec -= recTime->tv_sec;
return sub.tv_sec *
1000.0 + sub.tv_usec / 1000.0;
//转换单位为毫秒
}
unsigned short checkSum(unsignedshort * icmp,int size){
unsigned int sum =0;
while (size>1) {
sum = sum + *icmp;
icmp += 1;
//这里不加2是因为short类型指针每次移动2字节
size = size - 2;
//16位的方式求和
}
if (size == 1) {
sum = sum + *icmp;
}
//加完了如果有进位就,一定是第16位是1,让低位加1即可
sum = (sum >> 16) + (sum &
0xffff);
//只有有符号数有反码,无符号数没有反码的概念
return (unsignedshort)~sum;
}
void packIcmp(char * buf,int sequence){
struct icmp * icmp = (struct icmp *)buf;
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
icmp->icmp_cksum = 0;
icmp->icmp_id = getpid();
icmp->icmp_seq = sequence;
gettimeofday((struct timeval *)(icmp->icmp_data),0);
icmp->icmp_cksum = checkSum((unsigned
short *)icmp, sizeof(struct icmp));
}
int unpack(char * buf,ssize_t size,char * addr){
struct ip * ip;
// struct MyIcmp * icmp;
struct icmp * icmp;
int ipHLen;
int icmpLen;
struct timeval t;
float time;
//解析ip报文只为了找到icmp起始位置:
ip = (struct ip *)buf;
ipHLen = ip->ip_hl << 2;//因为首部长度以4字节位单位,但计算机以字节为单位
//找到icmp报文的起始位置:
icmp = (struct icmp *)(buf + ipHLen);
//解析icmp报文:
icmpLen = (int)(size-ipHLen);
if (icmpLen <
8) {
printf("ICMP报文长度小于8!\n");
return 0;
}
//判断是不是回显报文:
if (icmp->icmp_type != ICMP_ECHOREPLY || icmp->icmp_id != getpid()) {
printf("不是回显ICMP报文!\n");
return 0;
}
//解析时间:
gettimeofday(&t, 0);//0表示不使用时区
time = timediff((struct timeval *)icmp->icmp_data, &t);
//解析打印:
printf("from %s: icmp_seq=%d ttl=%d time=%f ms \n",addr,icmp->icmp_seq,ip->ip_ttl,time);
return
1;
}
int main(int argc,const
char * argv[]) {
struct sockaddr_in sendAdd;
memset(&sendAdd, 0,
sizeof(sendAdd));
unsigned int recAddInt =sizeof(struct sockaddr_in);
char recBuf[128];
char sendBuf[128];
//清空sendIcmp缓冲区的数据,清零:
memset(recBuf,0,128);
memset(sendBuf,0,128);
int sockfd;
int sequence =
0;
ssize_t recNum;
in_addr_t inadd;
char input[20];
char * pInput;
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) {
printf("原始套接字创建出错!\n");
exit(1);//异常退出
}
//设置目的IP:
printf("请输入要Ping的地址(点分十进制):\n");
scanf("%s",input);
pInput = input;
inadd = inet_addr(pInput);//将点分十进制转换成数字
//填充sendAdd结构体:
sendAdd.sin_addr.s_addr = inadd;
sendAdd.sin_family = AF_INET;
printf("IP: %s \n",inet_ntoa(sendAdd.sin_addr));
while(1) {//循环次:
//封装ICMP报文:
packIcmp(sendBuf,sequence);
//发送:
//需要将sockaddr_in指针转换成sockaddr
if ((sendto(sockfd, sendBuf,
64, 0,(struct sockaddr *)&sendAdd,sizeof(sendAdd))) == -1) {
printf("发送sento函数调用返回-1!\n");
continue;
}
//接收:(需要记录函数返回值,表示收到的字节数)
if ((recNum = recvfrom(sockfd, recBuf,sizeof(recBuf),
0, (struct sockaddr *)&sendAdd, &recAddInt)) == -1) {
printf("接收recfrom函数调用返回-1!\n");
continue;
}else{
//解析:
if (!unpack(recBuf,recNum,inet_ntoa(sendAdd.sin_addr))) {
printf("unpack失败!\n");
}
}
sleep(1);//等一秒;
sequence = sequence+1;//icmp报文序号加一
}
return
0;
}
#include <string.h>
#include <sys/socket.h>//socket()
#include <stdlib.h>
#include <unistd.h>//getpid
#include <arpa/inet.h>//IPPROTO_ICMP
#include <sys/time.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>//ICMP_ECHO
float timediff(struct timeval * recTime,struct timeval * nowTime){
struct timeval sub = *nowTime;
if ((sub.tv_usec -= recTime->tv_usec) <
0)
{
--(sub.tv_sec);
sub.tv_usec += 1000000;
}
sub.tv_sec -= recTime->tv_sec;
return sub.tv_sec *
1000.0 + sub.tv_usec / 1000.0;
//转换单位为毫秒
}
unsigned short checkSum(unsignedshort * icmp,int size){
unsigned int sum =0;
while (size>1) {
sum = sum + *icmp;
icmp += 1;
//这里不加2是因为short类型指针每次移动2字节
size = size - 2;
//16位的方式求和
}
if (size == 1) {
sum = sum + *icmp;
}
//加完了如果有进位就,一定是第16位是1,让低位加1即可
sum = (sum >> 16) + (sum &
0xffff);
//只有有符号数有反码,无符号数没有反码的概念
return (unsignedshort)~sum;
}
void packIcmp(char * buf,int sequence){
struct icmp * icmp = (struct icmp *)buf;
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
icmp->icmp_cksum = 0;
icmp->icmp_id = getpid();
icmp->icmp_seq = sequence;
gettimeofday((struct timeval *)(icmp->icmp_data),0);
icmp->icmp_cksum = checkSum((unsigned
short *)icmp, sizeof(struct icmp));
}
int unpack(char * buf,ssize_t size,char * addr){
struct ip * ip;
// struct MyIcmp * icmp;
struct icmp * icmp;
int ipHLen;
int icmpLen;
struct timeval t;
float time;
//解析ip报文只为了找到icmp起始位置:
ip = (struct ip *)buf;
ipHLen = ip->ip_hl << 2;//因为首部长度以4字节位单位,但计算机以字节为单位
//找到icmp报文的起始位置:
icmp = (struct icmp *)(buf + ipHLen);
//解析icmp报文:
icmpLen = (int)(size-ipHLen);
if (icmpLen <
8) {
printf("ICMP报文长度小于8!\n");
return 0;
}
//判断是不是回显报文:
if (icmp->icmp_type != ICMP_ECHOREPLY || icmp->icmp_id != getpid()) {
printf("不是回显ICMP报文!\n");
return 0;
}
//解析时间:
gettimeofday(&t, 0);//0表示不使用时区
time = timediff((struct timeval *)icmp->icmp_data, &t);
//解析打印:
printf("from %s: icmp_seq=%d ttl=%d time=%f ms \n",addr,icmp->icmp_seq,ip->ip_ttl,time);
return
1;
}
int main(int argc,const
char * argv[]) {
struct sockaddr_in sendAdd;
memset(&sendAdd, 0,
sizeof(sendAdd));
unsigned int recAddInt =sizeof(struct sockaddr_in);
char recBuf[128];
char sendBuf[128];
//清空sendIcmp缓冲区的数据,清零:
memset(recBuf,0,128);
memset(sendBuf,0,128);
int sockfd;
int sequence =
0;
ssize_t recNum;
in_addr_t inadd;
char input[20];
char * pInput;
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) {
printf("原始套接字创建出错!\n");
exit(1);//异常退出
}
//设置目的IP:
printf("请输入要Ping的地址(点分十进制):\n");
scanf("%s",input);
pInput = input;
inadd = inet_addr(pInput);//将点分十进制转换成数字
//填充sendAdd结构体:
sendAdd.sin_addr.s_addr = inadd;
sendAdd.sin_family = AF_INET;
printf("IP: %s \n",inet_ntoa(sendAdd.sin_addr));
while(1) {//循环次:
//封装ICMP报文:
packIcmp(sendBuf,sequence);
//发送:
//需要将sockaddr_in指针转换成sockaddr
if ((sendto(sockfd, sendBuf,
64, 0,(struct sockaddr *)&sendAdd,sizeof(sendAdd))) == -1) {
printf("发送sento函数调用返回-1!\n");
continue;
}
//接收:(需要记录函数返回值,表示收到的字节数)
if ((recNum = recvfrom(sockfd, recBuf,sizeof(recBuf),
0, (struct sockaddr *)&sendAdd, &recAddInt)) == -1) {
printf("接收recfrom函数调用返回-1!\n");
continue;
}else{
//解析:
if (!unpack(recBuf,recNum,inet_ntoa(sendAdd.sin_addr))) {
printf("unpack失败!\n");
}
}
sleep(1);//等一秒;
sequence = sequence+1;//icmp报文序号加一
}
return
0;
}
相关文章推荐
- Linux下用C语言实现Ping程序功能
- 在linux中用C语言实现ping命令的部分功能
- Linux下用C语言实现Ping程序功能
- C语言实现Linux系统下ls命令的过滤文件功能
- 在linux中用C语言实现ping命令的部分功能
- 在linux中用C语言实现ping命令的部分功能
- Linux下用C语言实现Ping程序功能
- C实现简单TCP的C/S模型(Linux & Mac OS系统)
- 用C语言实现Ping程序功能
- linux下ping的C语言实现
- 轻松实现 Linux系统下互联网过滤功能(转)
- Linux下获得系统时间的C语言的实现方法
- Linux中实现MSDN的功能查系统调用
- (转载)用C语言实现Ping程序功能
- scp:实现网络中Linux系统下文件互相拷贝功能
- 用C语言实现Ping程序功能
- Linux下获得系统时间的C语言的实现方法
- Linux系统实现HTTP服务的URLrewrite功能
- Linux下获得系统时间的C语言的实现方法[转]
- 用C语言实现Ping程序功能