【问题标题】:convert ip address to a single number将ip地址转换为单个数字
【发布时间】:2017-04-30 15:07:43
【问题描述】:

我有一个包含 100 多个 IP 地址的文件(点分十进制,例如 169.23.43.12)。现在我需要读取所有的 IP 地址并按升序排序。为此,首先我尝试将所有的ip地址转换为其等效的整数。我创建了一个c++函数来转换ip地址,但它不适用于大ip地址,例如255.250.120.100。我尝试使用inet_aton() 和inet_ntoa()。但是使用这两个,我无法对 IP 地址进行排序。所以,请给我一个想法,将 IP 地址转换为可以排序的形式。下面是一些代码,我尝试使用这些代码对 IP 地址进行排序,但没有奏效。

struct sockaddr_in 羚羊[2]; char *some_addr;

inet_aton("60.0.0.4", &antelope[0].sin_addr); // store IP in antelope
inet_aton("10.0.0.2", &antelope[1].sin_addr); // store IP in antelope
std::sort(antelope,antelope+2);
cout<<inet_ntoa(antelope[0].sin_addr)<<endl;
cout<<inet_ntoa(antelope[1].sin_addr)<<endl;

【问题讨论】:

  • 什么不起作用?错误是什么? std::sort 不知道如何订购 sockaddr_in 结构。
  • std::sort 给出了一些错误。那么,在使用 inet_aton() 之后,我该如何对它们进行排序呢?你知道任何排序它们的程序吗?
  • 你用过无符号整数吗?如果您使用有符号整数,则可能会发生您遇到的行为。
  • 我在自己的函数中使用无符号整数将 IP 地址转换为整数。它适用于像 10.10.127.12 这样的小型 IP 地址。当我在 32 位操作系统机器中输入 255.234.100.3 之类的 IP 地址时,它会给出准确的结果。但它在 64 位操作系统机器中给出了非常大的数字。

标签: c++ sorting ip-address


【解决方案1】:

您可以使用 struct sokaddr_in 的自定义比较器来做到这一点。下面的 sn-p 解释了我的意思。这种方法的优点是您可以为 IPv6 自定义比较器并包含端口号。如果 IP 地址相同,还有其他东西。

    #include <iostream>
    #include <algorithm>
    #include <arpa/inet.h>


    struct CompareSockAddr_in
    {
        bool operator ()(struct sockaddr_in ip1,struct sockaddr_in ip2){
            // use return ip1.sin_addr.s_addr < ip2.sin_addr.s_addr; for ascending order
return ip1.sin_addr.s_addr > ip2.sin_addr.s_addr;
        }
    };

    int main()
    {
        struct sockaddr_in antelope[2];

        inet_pton(AF_INET, "10.0.0.2", &(antelope[0].sin_addr));
        inet_pton(AF_INET, "60.0.0.4", &(antelope[1].sin_addr));

        std::cout<<inet_ntoa(antelope[0].sin_addr)<<std::endl;
        std::cout<<inet_ntoa(antelope[1].sin_addr)<<std::endl;
        std::sort(antelope,antelope+2,CompareSockAddr_in());

        std::cout<<"Sorted List...\n";

        std::cout<<inet_ntoa(antelope[0].sin_addr)<<std::endl;
        std::cout<<inet_ntoa(antelope[1].sin_addr)<<std::endl;

        return 0;
    }

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    使用std::istringstream 将字符串格式的 IPv4 地址转换为无符号整数的解决方案。

    #include <sstream>
    
    uint32_t convert( const std::string& ipv4Str )
    {
        std::istringstream iss( ipv4Str );
        
        uint32_t ipv4 = 0;
        
        for( uint32_t i = 0; i < 4; ++i ) {
            uint32_t part;
            iss >> part;
            if ( iss.fail() || part > 255 ) {
                throw std::runtime_error( "Invalid IP address - Expected [0, 255]" );
            }
            
            // LSHIFT and OR all parts together with the first part as the MSB
            ipv4 |= part << ( 8 * ( 3 - i ) );
    
            // Check for delimiter except on last iteration
            if ( i != 3 ) {
                char delimiter;
                iss >> delimiter;
                if ( iss.fail() || delimiter != '.' ) {
                    throw std::runtime_error( "Invalid IP address - Expected '.' delimiter" );
                }
            }
        }
        
        return ipv4;
    }
    

    示例结果

    "0.0.0.5"         =>          5
    "192.168.0.5"     => 3232235525
    "255.250.120.100" => 4294604900
    "255.255.255.255" => 4294967295
    

    【讨论】:

      【解决方案3】:

      将地址转换为无符号整数。代码可能如下所示:

      //  If ip is 132.152.25.103, then unsigned int IP = {132, 152, 25, 103};
      unsigned int identifier = 0;
      identifier = ((IP[0]*255 + IP[1])*255 + IP[2])*255 + IP[3];
      

      将所有标识符插入某个向量/数组并对其进行排序。

      【讨论】:

      • 256,而不是 255。左移 (
      【解决方案4】:

      第三个 inet_pton 参数是一个指向 in_addr 结构的指针。
      在成功调用inet_pton 后,in_addr 结构将填充地址信息。 该结构的 S_addr 字段包含按网络字节顺序(倒序)的 IP 地址。 ntohl 函数会将地址从网络字节顺序转换为主机字节顺序。

      Example : 
      
      #include <arpa/inet.h>
      uint32_t NodeIpAddress::getIPv4AddressInteger(std::string IPv4Address) {
          int result;
          uint32_t IPv4Identifier = 0;
          struct in_addr addr;
          // store this IP address in sa:
          result = inet_pton(AF_INET, IPv4Address.c_str(), &(addr));
          if (result == -1) {         
      gpLogFile->Write(LOGPREFIX, LogFile::LOGLEVEL_ERROR, _T("Failed to convert IP %hs to IPv4 Address. Due to invalid family of %d. WSA Error of %d"), IPv4Address.c_str(), AF_INET, result);
          }
          else if (result == 0) {
              gpLogFile->Write(LOGPREFIX, LogFile::LOGLEVEL_ERROR, _T("Failed to convert IP %hs to IPv4"), IPv4Address.c_str());
          }
          else {
              IPv4Identifier = ntohl(*((uint32_t *)&(addr)));
          }
          return IPv4Identifier;
      }
      

      【讨论】:

        猜你喜欢
        • 2011-02-25
        • 2017-07-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-23
        相关资源
        最近更新 更多