程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> linux:C語言通過ICMP協議判斷局域網內部主機是否存活,linuxicmp

linux:C語言通過ICMP協議判斷局域網內部主機是否存活,linuxicmp

編輯:C++入門知識

linux:C語言通過ICMP協議判斷局域網內部主機是否存活,linuxicmp


  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 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved