设为首页 加入收藏

TOP

linux:C语言通过ICMP协议判断局域网内部主机是否存活(一)
2017-10-13 10:28:11 】 浏览:8931
Tags:linux 语言 通过 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 timeva l *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 timeva l *)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 timeva l 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
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇线程互斥中双线程对资源按序访问.. 下一篇C++ 头文件系列(deque)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目