C++ Exercises(十七)---网际校验和算法

简介:
 在《基于ARP协议获取局域网内主机MAC地址》中使用了WinpCap来发送ARP请求,查询局域网内主机MAC地址,这篇来试试直接用Windows API函数来实现,最后再来探索用于IP,TCP,UDP等众多协议的网际校验和算法。

1,查询局域网主机MAC地址

复制代码
#include <WinSock2.h>
#include <IPHlpApi.h>
#include <iostream>
using namespace std;

#pragma comment(lib,"Iphlpapi")
#pragma comment(lib,"Ws2_32")

int _tmain(int argc, _TCHAR* argv[])
{
    MIB_IPADDRTABLE* pIPAddrTable = (MIB_IPADDRTABLE*)malloc(sizeof(MIB_IPADDRTABLE));
    ULONG dwSize=0,dwRetVal=0;
    if (GetIpAddrTable(pIPAddrTable,&dwSize,0)==ERROR_INSUFFICIENT_BUFFER)
    {
        free(pIPAddrTable);
        pIPAddrTable = (MIB_IPADDRTABLE*)malloc(dwSize);
    }
    if ((dwRetVal=GetIpAddrTable(pIPAddrTable,&dwSize,0))==NO_ERROR)
    {
        ULONG ulHostIp = ntohl(pIPAddrTable->table[0].dwAddr); //本机IP
        ULONG ulHostMask = ntohl(pIPAddrTable->table[0].dwMask); //子网掩码
        for (ULONG i= 1;i<(~ulHostMask);++i)
        {
            static ULONG ulNo = 0;
            HRESULT hr;
            IPAddr ipAddr;
            ULONG pulMac[2];
            ULONG ulLen;
            ipAddr = htonl(i+(ulHostIp&ulHostMask));
            memset(pulMac,0xff,sizeof(pulMac));
            ulLen = 6;
            hr = SendARP(ipAddr,0,pulMac,&ulLen); //发送ARP请求
            if (ulLen==6)
            {
                ulNo++;
                PBYTE pbHexMax = (PBYTE)pulMac;
                unsigned char * strIpAddr = (unsigned char *)(&ipAddr);
                printf("%d:MAC地址% 02X:% 02X:% 02X:% 02X:% 02X:% 02X IP地址% d. % d. % d. % d\n",ulNo,pbHexMax[0],pbHexMax[1],pbHexMax[2],pbHexMax[3],pbHexMax[4],pbHexMax[5],strIpAddr[0],strIpAddr[1],strIpAddr[2],strIpAddr[3]);
            }
        }
    }
    else
    {
        printf("失败");
    }
    printf("结束!\n");
    free(pIPAddrTable);
    return 0;
}
复制代码
2,获取本机网卡信息
复制代码
#include <WinSock2.h>
#include <IPHlpApi.h>
#include <iostream>
using namespace std;

#pragma comment(lib,"Iphlpapi")
#pragma comment(lib,"Ws2_32")

int _tmain(int argc, _TCHAR* argv[])
{
    PIP_ADAPTER_INFO pAdapterInfo;
    PIP_ADAPTER_INFO pAdapter = NULL;
    DWORD dwRetVal = 0;
    pAdapterInfo = (IP_ADAPTER_INFO*)malloc(sizeof(IP_ADAPTER_INFO));
    ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
    dwRetVal = GetAdaptersInfo(pAdapterInfo,&ulOutBufLen);
    if (dwRetVal==ERROR_BUFFER_OVERFLOW)
    {
        free(pAdapterInfo);
        pAdapterInfo = (IP_ADAPTER_INFO*)malloc(ulOutBufLen);
        dwRetVal = GetAdaptersInfo(pAdapterInfo,&ulOutBufLen);
    }
    if (dwRetVal==NO_ERROR)
    {
        pAdapter = pAdapterInfo;
        while (pAdapter)
        {
            printf("适配器名称:\t% s\n",pAdapter->AdapterName);
            printf("适配器描述信息:\t% s\n",pAdapter->Description);
            printf("MAC地址:\t% 02X:% 02X:% 02X:% 02X:% 02X:% 02X\n",pAdapter->Address[0],pAdapter->Address[1],
                pAdapter->Address[2],pAdapter->Address[3],pAdapter->Address[4],pAdapter->Address[5]);
            printf("IP地址:\t% s\n",pAdapter->IpAddressList.IpAddress.String);
            printf("子网掩码:\t% s\n",pAdapter->IpAddressList.IpMask.String);
            printf("网关地址:\t% s\n",pAdapter->GatewayList.IpAddress.String);
            if (pAdapter->DhcpEnabled)
            {
                printf("DHCP enabled: yes\n");
                printf("DHCP服务器:\t% s\n",pAdapter->DhcpServer.IpAddress.String);
                printf("租约:% ld\n",pAdapter->LeaseObtained);
            }
            else
            {
                printf("DHCP enabled:no\n");
            }
            if (pAdapter->HaveWins)
            {
                printf("Have Wins:Yes\n");
                printf("Primary Wins Server:\t% s\n",pAdapter->PrimaryWinsServer.IpAddress.String);
                printf("Secondary Server:\t% s\n",pAdapter->SecondaryWinsServer.IpAddress.String);
            }
            else
            {
                printf("Have Wins:No\n");
            }
            pAdapter = pAdapter->Next;
        }
    }
    else
    {
        printf("失败\n");
    }
    return 0;
}
复制代码
3,网际校验和(internet checksum)算法

      IP,TCP,UDP等许多协议的头部都设置了校验和项,计算校验和的算法一般采用网际校验和算法,它将被校验的数据按16位进行划分(若数据字节长度为奇数,则在数据尾部补一个字节0),对每16位求反码和,然后再对和取反码。

复制代码
#include<iostream>
#include<fstream>
using namespace std;
#include<winsock.h>            // 本机字节序转换为网络字节序:htons
#pragma comment(lib, "WS2_32.LIB")

/**************************************************************************
 * 计算给定数据的校验和
 *
 *        输入参数:
 *            pBuffer        指向需要校验的数据缓冲区
 *            nSize        需要校验的数据的大小,以字节为单位
 *
 *        返回值:
 *            16位的校验结果
 *
 **************************************************************************/
unsigned short checksum_calculating(unsigned short *pBuffer, int nSize)
{
    unsigned long dwCksum = 0;        // 32位累加和
    // 以两字节为单位反复累加
    while(nSize > 1)
    {
        dwCksum += *pBuffer++;
        nSize -= sizeof(unsigned short);
    }
    // 如果总字节数为奇数则加上最后一个字节
    if (nSize)
    {
        dwCksum += *(unsigned char*) pBuffer;
    }
    // 将位累加和的高位与低位第一次相加
    dwCksum = (dwCksum >> 16) + (dwCksum & 0xffff);
    // 将上一步可能产生的高位进位再次与低位累加
    dwCksum += (dwCksum >> 16);
    // 返回位校验和
    return (unsigned short) (~dwCksum);
}


int main(int argc, char * argv[])
{
        
    // 创建输入文件流
    ifstream fInfile;
    fstream fOutfile; // 创建输出文件流
    fInfile.open(argv[1], ios::in|ios::binary); // 以二进制方式打开指定的输入文件
    fInfile.seekg(0, ios::end); // 把文件指针移到文件末尾
    unsigned short wLen = (unsigned short)fInfile.tellg();// 取得输入文件的长度
    fInfile.seekg(0, ios::beg); // 文件指针位置初始化
    // 定义数据报缓冲区,缓冲区大小为+wLen ,其中为数据报类型字段、长度字段
    // 以及校验和字段的长度和,wLen为数据字段长度,即输入文件长度(以字节为单位)
    char * pBuf = new char[4 + wLen];
    pBuf[0] = unsigned char(0xab);        // 给数据报类型字段赋值,这里随便弄了个0Xab
    pBuf[1] = unsigned char(wLen);        // 给数据报长度字段赋值
    *(unsigned short *)(pBuf + 2) = 0;    // 计算校验和之前,校验和字段先置为0
    fInfile.read(pBuf+4, wLen);            // 根据输入文件填充数据报的数据字段
    // 计算校验和并把结果填入到数据报的校验和字段
    *(unsigned short *)(pBuf+2) = checksum_calculating((unsigned short *)pBuf,4+wLen);
    // 输出校验和计算结果
    cout.width(4);                    
    cout << "校验和为:x" << hex << htons( *(unsigned short *)(pBuf+2) )
         << "    (以网络顺序显示)"<< endl;
    // 以二进制方式打开输出文件
    fOutfile.open(argv[2],ios::in|ios::out|ios::binary|ios::trunc);
    // 将pBuf中的数据报写入输出文件
    fOutfile.write((char *)pBuf, wLen+4);
    cout<< "数据报已成功保存在" << argv[2] << "文件中!" << endl;
    delete [] pBuf;        // 释放数据报缓冲区
    fInfile.close();    // 关闭输入文件流
    fOutfile.close();    // 关闭输出文件流
    return 0;
}
复制代码


本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2009/01/05/1369761.html,如需转载请自行联系原作者
目录
相关文章
|
2月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
1天前
|
算法 安全 C++
用 C++ 算法控制员工上网的软件,关键逻辑是啥?来深度解读下
在企业信息化管理中,控制员工上网的软件成为保障网络秩序与提升办公效率的关键工具。该软件基于C++语言,融合红黑树、令牌桶和滑动窗口等算法,实现网址精准过滤、流量均衡分配及异常连接监测。通过高效的数据结构与算法设计,确保企业网络资源优化配置与安全防护升级,同时尊重员工权益,助力企业数字化发展。
21 4
|
2月前
|
存储 算法 C++
高精度算法(加、减、乘、除,使用c++实现)
高精度算法(加、减、乘、除,使用c++实现)
693 0
高精度算法(加、减、乘、除,使用c++实现)
|
2月前
|
算法 数据处理 C++
c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解
这些算法是C++ STL中处理和组织数据的强大工具,能够高效地实现复杂的数据处理逻辑。理解它们的差异和应用场景,将有助于编写更加高效和清晰的C++代码。
51 0
|
2月前
|
存储 算法 决策智能
【算法】博弈论(C/C++)
【算法】博弈论(C/C++)
|
2月前
|
存储 算法 C++
【算法】哈希映射(C/C++)
【算法】哈希映射(C/C++)
|
2月前
|
机器学习/深度学习 人工智能 算法
【算法】最长公共子序列(C/C++)
【算法】最长公共子序列(C/C++)
|
2月前
|
人工智能 算法 BI
一篇带你速通差分算法(C/C++)
一篇带你速通差分算法(C/C++)
|
2月前
|
人工智能 算法 C++
一篇带你速通前缀和算法(C/C++)
一篇带你速通前缀和算法(C/C++)
|
2月前
|
存储 算法 C++
弗洛伊德(Floyd)算法(C/C++)
弗洛伊德(Floyd)算法(C/C++)