C++实现通过ICMP实现ping, 计算网络抖动,时延与丢包率

目的

通过C++编程实现ping, 也算是对于SOCKET编程初步了解掌握。

  • 了解ICMP协议
  • 了解对应socket编程

关于ICMP

请参考我的博客Ping工作原理

socket 编程实现ICMP

Ping 使用 Internet 控制消息协议(ICMP)来测试主机之间的连通性。当用客户端发送一个 ping 请求时,则对应的发送一个 ICMP Echo 请求消息到目标主机,并等待目标主机回复一个 ICMP Echo 回应消息。如果目标主机接收到请求并且网络连接正常,则会返回一个回应消息,表示主机之间的网络连接是正常的。如果目标主机没有收到请求消息或网络连接不正常,则不会有回应消息返回。

编译error

  • winsock2.h 与 windows.h 先后顺序导致编译错误
    在Windows环境下编程不可避免的会用到windows.h和winsock.h头文件,在默认情况下windows.h头文件会包含winsock.h,此时当尝试包含winsock.h时就会出现头文件定义冲突的情况。解决这个冲突的方式有两种,第一种,在头部定义#define WIN32_LEAN_AND_MEAN来主动去除winsock.h头文件包含。第二种是将#include <winsock2.h>头文件,放在#include<windows.h>之前。两种方式均可,这些方法在进行Windows套接字编程时非常重要,可以防止头文件冲突,确保编译顺利进行。

  • IPExport.h导致编译错误
    还有一种是我遇到的 OptionsData 未知重写说明符, Data 未知重写说明符
    需要将如下注释掉就行, 具体原因后续有时间整理下。

//#include <iphlpapi.h>
//#include <icmpapi.h>

代码

  • ICMPDataHeader.h

相关头文件声明 与 数据定义


#pragma once

#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <vector>
#include <cmath>
#include <chrono>
#include <ctime>
//#include <iphlpapi.h>
//#include <icmpapi.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>


#pragma comment(lib, "ws2_32.lib")
//#pragma comment(lib, "iphlpapi.lib")

#define IP_RECORD_ROUTE  0x7


// IP header structure
typedef struct _iphdr
{
   
    //Suppose the BYTE_ORDER is LITTLE_ENDIAN
    unsigned int   h_len:4;        // Length of the header
    unsigned int   version:4;      // Version of IP
    unsigned char  tos;            // Type of service
    unsigned short total_len;      // Total length of the packet
    unsigned short id;             // Unique identification
    unsigned short frag_offset;    // Fragment offset
    unsigned char  ttl;            // Time to live
    unsigned char  protocol;       // Protocol (TCP, UDP etc)
    unsigned short checksum;       // IP checksum
    unsigned int   sourceIP;       // Source IP
    unsigned int   destIP;         // Destination IP
} IpHeader;

#define ICMP_ECHO        8
#define ICMP_ECHOREPLY   0
#define ICMP_MIN         8 // Minimum 8-byte ICMP packet (header)

// ICMP header structure
// This is not the standard header, but we reserve space for time
typedef struct _icmphdr
{
   
    BYTE   i_type;
    BYTE   i_code;                 // Type sub code
    USHORT i_cksum;
    USHORT i_id;
    USHORT i_seq;
    ULONG  timestamp;
} IcmpHeader;

// IP option header - use with socket option IP_OPTIONS
typedef struct _ipoptionhdr
{
   
    unsigned char code;        // Option type
    unsigned char len;         // Length of option hdr
    unsigned char ptr;         // Offset into options
    unsigned long addr[9];     // List of IP addrs
} IpOptionHeader;

#define DEF_PACKET_SIZE  32        // Default packet size
#define MAX_PACKET       1024      // Max ICMP packet size
#define MAX_IP_HDR_SIZE  60        // Max IP header size w/options


  • 关键核心代码 cpp
校验函数
#include "icmppacketprocessor.h"


ICMPPacketProcessor::ICMPPacketProcessor(QObject* parent)
    :QObject{
   parent}
{
   

}

ICMPPacketProcessor::~ICMPPacketProcessor()
{
   
    if(lpdest){
   
        delete lpdest;
    }
}

unsigned short ICMPPacketProcessor::checksum(unsigned short *buffer, int size)
{
   
    unsigned long cksum=0;
    while(size > 1){
   
        cksum += *buffer++;
        size -= sizeof(unsigned short);
    }
    if(size)
    {
   
        cksum += *(UCHAR*)buffer;
    }
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >>16);
    return (unsigned short)(~cksum);
}

// Function: FillICMPData
// Description:
//    Helper function to fill in various fields for our ICMP request
void ICMPPacketProcessor::fillICMPData(char *icmp_data, int datasize)
{
   
    IcmpHeader *icmp_hdr = NULL;
    char *datapart = NULL;

    icmp_hdr = (IcmpHeader*)icmp_data;
    icmp_hdr->i_type = ICMP_ECHO; // Request an ICMP echo, type is 8
    icmp_hdr->i_code = 0;    // code is 0
    icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
    icmp_hdr->i_cksum = 0;
    icmp_hdr->i_seq = 0;

    datapart = icmp_data + sizeof(IcmpHeader);
    // Place some junk in the buffer
    memset(datapart, 'E' , datasize - sizeof(IcmpHeader));
}
// Function: DecodeIPOptions
// Description:
//    If the IP option header is present, find the IP options
//    within the IP header and print the record route option values
void ICMPPacketProcessor::decodeIPOptions(char *buf, int bytes)
{
   
    IpOptionHeader *ipopt = NULL;
    IN_ADDR         inaddr;
    int             i;
    HOSTENT        *host = NULL;

    ipopt = (IpOptionHeader *)(buf + 20);

    printf("Record Route:   ");
    for(i = 0; i < (ipopt->ptr / 4) - 1; i++)
    {
   
        inaddr.S_un.S_addr = ipopt->addr[i];
        if (i != 0) printf("   ");
        host = gethostbyaddr((char *)&inaddr.S_un.S_addr, sizeof(inaddr.S_un
  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

道阻且长,行则降至

无聊,打赏求刺激而已

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值