linux:C语言通过ICMP局域网内部主机是否存活

  ICMP协议

  ICMP(Internet Control Message,网际控制报文协议)是为网关和目标主机而提供的一种差错控制机制,使它们在遇到差错时能把错误报告给报文源发方。

  ICMP协议是IP层的一个协议,但是由于差错报告在发送给报文源发方时可能也要经过若干子网,因此牵涉到路由选择等问题,所以ICMP报文需通过IP协议来发送。

  ICMP数据报的数据发送前需要两级封装:首先添加ICMP报头形成ICMP报文,再添加IP报头形成IP数据报。

  main.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <signal.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <setjmp.h>
#include <errno.h>
#include <sys/select.h>
#include <fcntl.h>
#define PACKET_SIZE 4096
/* 计算校验和的算法 */
unsigned short cal_chksum(unsigned short *addr,int len)
{
    int sum=0;
    int nleft = len;
    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;    /* 这里将 answer 转换成 int 整数 */
    }
    sum = (sum >> 16) + (sum & 0xffff);        /* 高位低位相加 */
    sum += (sum >> 16);        /* 上一步溢出时,将溢出位也加到sum中 */
    answer = ~sum;             /* 注意类型转换,现在的校验和为16位 */
    return answer;
}
int livetest(char* ip) {

    char    sendpacket[PACKET_SIZE];    /* 发送的数据包 */
    char    recvpacket[PACKET_SIZE];    /* 接收的数据包 */
    pid_t    pid;
    int    datalen = 56;    /* icmp数据包中数据的长度 */
    struct protoent *protocol;
    protocol = getprotobyname("icmp");
    int sockfd;
    int size = 50*1024;
    if((sockfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) < 0) {
        perror("socket error");
    }
    setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size) );

    struct sockaddr_in dest_addr;
    bzero(&dest_addr, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_addr.s_addr = inet_addr(ip);
    //send packet;
    int packsize;
    struct icmp *icmp;
    struct timeval *tval;
    icmp = (struct icmp*)sendpacket;
    icmp->icmp_type = ICMP_ECHO;    /* icmp的类型 */
    icmp->icmp_code = 0;            /* icmp的编码 */
    icmp->icmp_cksum = 0;           /* icmp的校验和 */
    icmp->icmp_seq = 1;       /* icmp的顺序号 */
    icmp->icmp_id = pid;            /* icmp的标志符 */
    packsize = 8 + datalen;   /* icmp8字节的头 加上数据的长度(datalen=56), packsize = 64 */
    tval = (struct timeval *)icmp->icmp_data;    /* 获得icmp结构中最后的数据部分的指针 */
    gettimeofday(tval, NULL); /* 将发送的时间填入icmp结构中最后的数据部分 */
    icmp->icmp_cksum = cal_chksum((unsigned short *)icmp, packsize);/*填充发送方的校验和*/

    if(sendto(sockfd, sendpacket, packsize, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < 0){
        perror("sendto error");
    }
    printf("send %d, send done\n",1 );
    int n;
    struct sockaddr_in from;
    int fromlen = sizeof(from);
    fcntl(sockfd, F_SETFL, O_NONBLOCK);
    struct timeval timeo = {1,0};
    fd_set set;
    FD_ZERO(&set);
    FD_SET(sockfd, &set);
    //read , write;
    int retval = select(sockfd+1, &set, NULL, NULL, &timeo);
    if(retval == -1) {
        printf("select error\n");
        return 0;
    }else if(retval == 0 ) {
        printf("timeout\n");
        return 0;
    }else{
        if( FD_ISSET(sockfd, &set) ){
            printf("host is live\n");
            return 1;
        }
    }
    // n = recvfrom(sockfd, recvpacket,sizeof(recvpacket), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen);
    // if(n<0) {
    //     perror("recvfrom error");
    // }else{
    //     printf("%d\n",n);
    // }
    //return 0;
}

int main(int argc, char* argv[]) {
    printf("%d\n" , livetest(argv[1]));
    return 0;
}

  

  参考:

    用C语言实现Ping程序功能:http://www.ibm.com/developerworks/cn/linux/network/ping/index.html

作者: NONO
出处:http://www.cnblogs.com/diligenceday/

QQ:287101329

微信:18101055830

时间: 2024-10-15 14:53:27

linux:C语言通过ICMP局域网内部主机是否存活的相关文章

Zabbix中使用ICMP ping来判断主机是否存活的问题

上一节配置了Simple check,现在来通过Simple check 用ICMP ping来监控充节点运行情况.Zabbix使用fping处理ICMP ping的请求,需要安装fping程序,安装完毕之后需要在zabinx_server.conf中的参数FpingLocation配置fping安装的路径.由于fping默认是root权限工作,而zabbix-server是zabbix用户运行的,所以需要对fping程序设置setuid权限,如果在自定义key的时候需要用到netstat命令,

linux上不了网,宿主机ping虚拟机通,虚拟机内部ping的同,但ping宿主机外网不通

背景介绍:搭建虚拟机linux环境,但linux上不了网,宿主机ping虚拟机通,虚拟机内部ping得通,ping宿主机外网不通,在ping外部网络的时候老是提示以下报错: From 192.168.93.130 icmp_seq=8 Destination Host Unreachable From 192.168.93.130 icmp_seq=8 Destination Host Unreachable 或者ping好久都没有反应 类似的情况遇到了几次,总结了一下遇到的原因 第一个原因,搭

虚拟机Linux安装Oracle容器并实现局域网其他主机访问查询

该文涉及Docker下Oracle容器的安装,主机端口的设置实现局域网内终端均能连接上Oracle数据库,图解如下: 一.关于Docker安装oracle容器可以参考下面博文: https://blog.csdn.net/qq_38380025/article/details/80647620 文中需要注意的地方是,建立容器没有使用目录挂载: docker run -d -p 1521:1521 --name oracle11g registry.cnhangzhou.aliyuncs.com/

嵌入式 Linux C语言——C语言基础

嵌入式 Linux C语言--C语言基础 一.数据类型 1.基本数据类型 数据类型是创建变量的模型.变量名是连续存储空间的别名,程序中使用变量命名存储空间,通过变量可以使用存储空间.变量所占的内存大小取决于创建变量的数据类型. 2.有符号和无符号 有符号数中数据类型的最高位用于标识数据的符号,最高位为1表示为负数,最高位为0表示为正数. 计算机中有符号数通常使用补码表示,正数的补码为正数本身,负数的补码为负数的绝对值的各位取反后加1. 计算机中无符号数通常使用原码表示,无符号数默认为正数,没有符

嵌入式linux C++语言(四)——类与对象

嵌入式linux C++语言(四)--类与对象 类的设计和使用如下: #include <iostream>#include <stdlib.h>#include <stdio.h>#include <string.h>using namespace std;class Stack{public:    Stack(int size=1024);    ~Stack();    void init();    bool isEmpty();    bool

嵌入式linux C++语言(二)——C++对C语言基础语法的扩展

嵌入式linux C++语言(二)--C++对C语言基础语法的扩展 C++是基于C语言扩展发展而来的面向对象的程序设计语言,本文将主要讨论C++语言基于C语言扩展的方面. 一.类型增强 1.类型检查更严格 在C语言中: const int a = 100; int *p = &a; 在C++语言中: const int a = 100;//必须在定义的时候初始化 const int *p = &a; 在C++语言中不能隐式转换数据类型. error: invalid conversion

嵌入式Linux C语言(三)——指针与函数

嵌入式Linux C语言(三)--指针与函数 指针对函数的功能有巨大的贡献,指针能够将数据传递给函数,并且允许函数对数据进行修改.指针对于函数的作用主要有两方面:将指针传递给函数和声明函数指针. 一.程序的栈和堆 程序的栈和堆是C语言程序运行的运行时元素. 1.程序栈 程序栈是支持函数执行的内存区域,通常和堆共享一块内存区域,通常程序栈占据内存区域的下部,堆用内存区域的上部.程序栈存放栈帧,栈帧存放函数参数和局部变量.调用函数时,函数的栈帧被推倒栈上,栈向上长出一个栈帧,当函数终止时,函数的栈帧

嵌入式 Linux C语言(七)——结构体

嵌入式 Linux C语言(六)--结构体 一.结构体简介 1.结构体定义 结构体定义一般有两种方法较为常用: 第一种方法: struct person{ char *name; unisgned int age; }; 第二种方法: typedef struct person{ char *name; unsigned int age; }Person; person实例声明如下: Person person;//声明一个person对象 Person *ptrPerson = (Person

嵌入式 Linux C语言(八)——存储类型、作用域、生命周期、链接属性

嵌入式 Linux C语言(八)--存储类型.作用域.生命周期.链接属性 一.存储类型 C语言中,每个变量和函数都有两个属性:数据类型和数据的存储类型. 变量的存储类型是指存储变量值的内存类型.变量的存储类型决定变量何时创建.何时销毁以及它的值将保持多久.计算机中有三个地方可以用于存储变量:普通内存,运行时堆和栈,硬件寄存器.变量的存储类型取决于声明变量的位置. C语言存储类别说明符: 说明符 用    法 auto 只在代码块内变量声明中被允许, 表示变量具有本地生存期 extern 出现在顶