【问题标题】:How do I increment an IP address represented as a string?如何增加表示为字符串的 IP 地址?
【发布时间】:2010-12-03 02:29:15
【问题描述】:

我有一个 char 类型的 IP 地址,例如 char ip = "192.123.34.134" 我想增加最后一个值 (134)。有谁我应该怎么做?我想,我应该将它转换为整数,然后再返回,但不幸的是我不知道如何? :( 我正在使用 C++。

请帮帮我!

谢谢,坎皮

【问题讨论】:

    标签: c++ string ip-address


    【解决方案1】:

    我会编写一个接受该格式字符串的方法。
    将其转换为 4 个整数。增量。 (重要检查范围)
    然后转回字符串。

    如果您想要更长期和更强大的表示 IP 地址的类。然后你维护类,并在需要时转换为字符串。

    #include <iostream>
    #include <istream>
    #include <sstream>
    #include <string>
    #include <stdexcept>
    
    
    
    class MyIp
    {
        struct Dot
        {};
        struct Byte
        {
            Byte(unsigned char& val)
                :m_val(val)
            {}
            unsigned char&  m_val;
        };
        friend std::istream& operator>>(std::istream& str,MyIp::Dot const& d);
        friend std::istream& operator>>(std::istream& str,MyIp::Byte const& b);
        friend std::ostream& operator<<(std::ostream& str,MyIp const& ip);
        public:
            MyIp(std::string const& ip)
            {
                std::stringstream str(ip);
                str >> Byte(ad[0]) >> Dot() >> Byte(ad[1]) >> Dot() >> Byte(ad[2]) >> Dot() >> Byte(ad[3]);
                std::string leftover;
                if (str >> leftover)
                {   throw std::runtime_error("InvalidIP: Long");
                }
            }
            void inc(int index)
            {
                if ((index >= 0) && (index <=3))
                {
                    ++ad[index];
                    if (ad[index] == 0)
                    {
                        inc(index-1);
                    }
                }
            }
        private:
            unsigned char   ad[4];
    };
    std::istream& operator>>(std::istream& str,MyIp::Dot const& d)
    {
        char x  = str.get();
        if (x != '.')
        {   throw std::runtime_error("Invalid IP: Dot");
        }
        return str;
    }
    std::istream& operator>>(std::istream& str,MyIp::Byte const& b)
    {
        unsigned int val;
        str >> val;
        if (!str || val > 255)
        {   throw std::runtime_error("Invalid IP: Val");
        }
        b.m_val = static_cast<unsigned char>(val);
        return str;
    }
    std::ostream& operator<<(std::ostream& str,MyIp const& ip)
    {
        return str  << static_cast<unsigned int>(ip.ad[0])
                    << "." << static_cast<unsigned int>(ip.ad[1])
                    << "." << static_cast<unsigned int>(ip.ad[2])
                    << "." << static_cast<unsigned int>(ip.ad[3]);
    }
    
    int main()
    {
        try
        {
            std::string ip("127.0.0.1");
    
            MyIp    addr(ip);
    
            std::cout << addr << "\n";
            addr.inc(3);
            std::cout << addr << "\n";
        }
        catch(std::exception const& e)
        {
            std::cout << "What: " << e.what() << "\n";
        }
    }
    

    【讨论】:

      【解决方案2】:

      您可以使用inet_addr 将IP 地址从字符串转换为整数,然后在操作后使用inet_ntoa 将其转换回字符串。

      有关这些功能的更多信息,请参阅the documentation,了解如何使用它们。

      这里有一个小函数可以满足你的需求:

      // NOTE: only works for IPv4.  Check out inet_pton/inet_ntop for IPv6 support.
      char* increment_address(const char* address_string)
      {
          // convert the input IP address to an integer
          in_addr_t address = inet_addr(address_string);
      
          // add one to the value (making sure to get the correct byte orders)
          address = ntohl(address);
          address += 1;
          address = htonl(address);
      
          // pack the address into the struct inet_ntoa expects
          struct in_addr address_struct;
          address_struct.s_addr = address;
      
          // convert back to a string
          return inet_ntoa(address_struct);
      }
      

      在 *nix 系统上包括 &lt;arpa/inet.h&gt;,在 Windows 上包括 &lt;winsock2.h&gt;

      【讨论】:

      • 我知道我的执行速度会更快,但这个答案肯定更正确。
      • 我只是假设您的意思是 inet_ntop 而不是 deprecated inet_ntoa,对吗? 对吗?
      • @R. Bemrose IPv6 使这个问题不必要地复杂化了。最初的问题表明该地址将采用点分四边形格式,这意味着仅 IPv4。如果您对用适用于 IPv6 地址的方法替换 htonl/ntohl 调用有任何建议,我会很乐意更新代码。
      • 我在 Windows 下使用 Dev-C++。如果我尝试编译您的代码,则会收到“in_addr_t”错误。 Dev-C++ 似乎无法识别这种类型。你能告诉我,我该如何解决这个问题?提前致谢!
      • 只需使用unsigned long 而不是in_addr_t。您可能还必须将 s_addr 中的 S 大写(所以它应该看起来像 S_addr。)我目前无法访问 Windows 计算机,所以我希望这样做。
      【解决方案3】:

      这个网站吃掉了我的标签,所以我会再试一次。我确信有一个库可以做这样的事情,但这应该可以工作(假设我的语法没有搞砸)足以让这个想法得到理解。

      伪代码:

      char[] ipAddress= "192.123.34.134";
      
      if (ipAddress[ipAddress.Length-1] == '9')
      {
          if(ipAddress[ipAddress.Length-2]=='9')
          {
              ipAddress[ipAddress.Length-1]='0';
              ipAddress[ipAddress.Length-2]='0';
              ipAddress[ipAddress.Length-3]=(char)ipAddress[ipAddress.Length-3]+1;
          }
          else
          {
              ipAddress[ipAddress.Length-2]=(char)ipAddress[ipAddress.Length-2]+1;
              ipAddress[ipAddress.Length-1]='0';
          }
      }
      else
      {
           ipAddress[ipAddress.Length-1]=(char)ipAddress[ipAddress.Length-1]+1;
      }
      

      【讨论】:

      • 192.123.34.255 呢?
      • 此时,我认为已经处理了那种范围检查。对我来说,我认为将 192.123.34.255 变成 192.123.35.0 是没有意义的,我认为其他解决方案会通过整数。
      • 呃,既然你提到了,x.x.x.99 或 x.x.x.9 也不起作用。我可以解决这些问题,但实际上,使用套接字库函数的上述答案更正确。
      【解决方案4】:

      快/脏!

      void increment(std::string& ip)
      {
          std::string::size_type dot = ip.find_last_of('.');
          std::stringstream stream(ip.substr(dot+1));
          int part = 0;
      
          stream >> part;
      
          part++;
      
          stream.str(""); stream.clear();
      
          stream << part;
      
          ip.replace(dot+1, std::string::npos, stream.str());
      }
      

      【讨论】:

      • 我在你编码的时候打字 :) 我的 C++ 技能生疏了,但你的技能看起来不错。好节目。
      【解决方案5】:

      您也可以使用最后一个“.”的位置。并从那里到最后转换为 int,将其提升 1,检查边界,然后将其转换为字符串并附加到基础部分。

      【讨论】:

        【解决方案6】:

        这可能不是很理智,但想想很有趣。

        由于 IP 地址空间是 32 位,您可以编写一个函数将 IP 地址转换为无符号的 32 位整数。然后您可以添加或减去 1 或任意数量,然后转换回 IP 地址。您不必担心范围检查。

        在 192.123.34.134 的伪代码中,你会这样做:

        int i = (192 << 24) + (123 << 16) + (34 << 8) + 134
        

        更一般地说,对于 a.b.c.d:

        int i = (a << 24) + (b << 16) + (c << 8) + d
        

        现在随心所欲地更改ii++i+=10000)并转换回来:

        String ip = (i >> 24) + "." + 
                    ((i >> 16) mod 256) + "." + 
                    ((i >> 8) mod 256) + "." + 
                    (i mod 256);
        

        请原谅语法 - 我无法编写 C++ 来拯救自己。

        MK

        【讨论】:

        • 这正是 inet_addr_t 是什么,就像尼尔的回答一样,所以不需要自己动手。所以不管它是否理智,这都是 C 程序员多年来一直在做的事情......
        • 如果我认为位旋转有点太硬核,我想我在 Java 世界里待得太久了,谢谢你的指点! (双关语原本不是有意的,但被发现时会保留。)
        【解决方案7】:
        int a,b,c,d;
        sscanf(str, "%d.%d.%d.%d", &a,&b,&c,&d);
        sprintf(str, "%d.%d.%d.%d\0", a,b,c,d+1);
        

        【讨论】:

          猜你喜欢
          • 2018-12-08
          • 1970-01-01
          • 2011-10-08
          • 2017-08-22
          • 2021-10-15
          • 1970-01-01
          • 2022-07-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多