代码之家  ›  专栏  ›  技术社区  ›  Bill the Lizard

如何验证字符串在C++中是一个有效的IPv4地址?

  •  43
  • Bill the Lizard  · 技术社区  · 16 年前

    我不需要验证IP地址是否可以访问或类似的情况。我只想验证该字符串是否为点四元(xxx.xxx.xxx.xxx)IPv4格式,其中xxx介于0和255之间。

    16 回复  |  直到 6 年前
        1
  •  50
  •   gary    6 年前

    你可能想要 inet_pton ,对于无效的af参数返回-1,对于无效的地址返回0,对于有效的IP地址返回+1。它同时支持IPv4和未来的IPv6地址。如果仍然需要编写自己的IP地址处理,请记住,标准的32位十六进制数是有效的IP地址。并非所有的IPv4地址都采用点分十进制表示法。

    这个函数既验证地址,也允许您在相关的套接字调用中使用相同的地址。

        2
  •  44
  •   Björn Pollex    11 年前

    Boost.Asio 提供类 ip::address . 如果只想验证字符串,可以这样使用:

    std::string ipAddress = "127.0.0.1";
    boost::system::error_code ec;
    boost::asio::ip::address::from_string( ipAddress, ec );
    if ( ec )
        std::cerr << ec.message( ) << std::endl;
    

    这也适用于十六进制和八进制四进制。这也是一个更加便携的解决方案。

        3
  •  33
  •   Bill the Lizard    11 年前

    我解决的办法是:

    bool Config::validateIpAddress(const string &ipAddress)
    {
        struct sockaddr_in sa;
        int result = inet_pton(AF_INET, ipAddress.c_str(), &(sa.sin_addr));
        return result != 0;
    }
    

    这适用于其他答案中提到的大多数情况。它不能识别八进制或十六进制格式的IP地址,但这对于我的应用程序是可以接受的。

        4
  •  17
  •   Mihai Limbășan    15 年前

    这看起来似乎很简单,但也有一些缺陷。例如,在前面的答案中发布的许多解决方案都假定四元数是以10为基数的,但四元数从零开始。 必须 被视为以8(八进制)为基数的数字,因此,例如以零开始并包含数字8或9的任何四部分都无效。即IP号码 192.168.1.010 192.168.1.10 但实际上 192.168.1.8 和IP号码 192.168.019.14 无效,因为第三个四进制包含无效的8位基数9。

    我强烈建议您使用操作系统或编译器环境中包含的套接字库提供的函数。

    编辑:(认为它是隐式的,但是)当然,你也可以有十六进制四次方,一个LA 192.168.1.0x0A 对于192.168.1.10,当然,您可以使用大写和小写字母a la来混合和匹配您的施虐内容。 0xC0.0xa8.1.010 192.168.1.8。如果你想玩得开心的话,可以试试用ping的例子。这只适用于跨平台(前一段时间在Linux、NetBSD和Win32下进行测试)。

    根据Kalusingh Gabbar的请求进一步编辑:例如,可以指定 192.1681.10 作为 0xc0a8010a 它仍然代表一个有效的IP号码,la:

    [mihailim@home ~]$ ping 0xc0a8010a
    PING 0xc0a8010a (192.168.1.10) 56(84) bytes of data.
    ^C
    --- 0xc0a8010a ping statistics ---
    3 packets transmitted, 0 received, 100% packet loss, time 2479ms
    
        5
  •  8
  •   Steve    16 年前

    这里有一个简单的方法。

    bool IsIPAddress(std::string & ipaddr)
        {    
    
        StringTokenizer quads(ipaddr,".");
    
        if (quads.countTokens() != 4) return false;
    
        for (int i=0; i < 4; i++)
          {
          std::string quad = quads.nextToken();
          for (int j=0; j < quad.length(); j++
             if (!isdigit(quad[j])) return false;
    
          int quad = atoi(quads.GetTokenAt(i));
          if (quad < 0) || (quad > 255)) return false;
          }
    
        return true;
        }
    
        6
  •  5
  •   Sachin Chavan bortzmeyer    12 年前

    如果你在窗户上,你可以利用 WSAStringToAddress 根据我们知道的返回值,如果传递的参数是有效的IP或者不是。这同时支持Windows 2000以后的IPv4和IPv6。

        7
  •  2
  •   Martin Cote    16 年前

    Boost.Regex 是合适的。

    bool validate_ip_address(const std::string& s)
    {
       static const boost::regex e("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
       return regex_match(s, e);
    }
    
        8
  •  2
  •   xan    16 年前

    如果你想自己写而不是用图书馆,那么

    atoi()将字符转换为整数,可以测试每个数字的范围,以及“.”之间的某些strcmp。还可以进行一些快速检查,例如字符串的长度(应小于16个字符(不包括空终止符)、点的数量。等。

    但是,使用现有代码可能要容易得多。

        9
  •  2
  •   Coding Mash desirejeet    12 年前

    下面是验证给定IPv4地址的C程序。我假设IP地址是十进制格式。请把你的想法告诉我。

      // strTokenFunction.cpp : Check if the specified address is a valid numeric IP address.
      // This function is equavalent to the IPAddress.TryParse() method in C#
    
    #include "stdafx.h"
    #include <stdio.h>
    #include <conio.h>
    #include <string.h>
    
    bool isValidIpAddress(char *st)
    {
        int num, i, len;
        char *ch;
    
        //counting number of quads present in a given IP address
        int quadsCnt=0;
    
        printf("Split IP: \"%s\"\n", st);
    
        len = strlen(st);
    
        //  Check if the string is valid
        if(len<7 || len>15)
            return false;
    
        ch = strtok(st, ".");
    
        while (ch != NULL) 
        {
            quadsCnt++;
            printf("Quald %d is %s\n", quadsCnt, ch);
    
            num = 0;
            i = 0;
    
            //  Get the current token and convert to an integer value
            while(ch[i]!='\0')
            {
                num = num*10;
                num = num+(ch[i]-'0');
                i++;
            }
    
            if(num<0 || num>255)
            {
                printf("Not a valid ip\n");
                return false;
            }
    
            if( (quadsCnt == 1 && num == 0) || (quadsCnt == 4 && num == 0))
            {
                printf("Not a valid ip, quad: %d AND/OR quad:%d is zero\n", quadsCnt, quadsCnt);
                return false;
            }
    
            ch = strtok(NULL, ".");
        }
    
        //  Check the address string, should be n.n.n.n format
        if(quadsCnt!=4)
        {
            return false;
        }
    
        //  Looks like a valid IP address
        return true;
    }
    
    int main() 
    {
        char st[] = "192.255.20.30";
        //char st[] = "255.255.255.255";
        //char st[] = "0.255.255.0";
    
        if(isValidIpAddress(st))
        {
            printf("The given IP is a valid IP address\n"); 
        }
        else
        {
            printf("The given IP is not a valid IP address\n");
        }
    }
    
        10
  •  2
  •   Ramadheer Singh    11 年前

    我也只使用了C stdlib函数,尽管它不支持上面提到的八进制四进制,但这不应该是一个问题,我可以很容易地添加该部分并将其提供给您。作为一个初学者(学生),直到现在我才知道在你的IP中有可能得到一个八进制数。我以为一定是小数。

        11
  •  1
  •   Marcin    16 年前

    使用Boost标记器和Boost字符分隔符可以很容易地完成这一任务。

    http://www.boost.org/doc/libs/1_37_0/libs/tokenizer/char_separator.htm

        12
  •  1
  •   EricSchaefer    16 年前

    如果您不想增加或TR1的开销,您可以搜索点,检查它们之间的字符是否是0到255之间的数字。

        13
  •  1
  •   Amir    13 年前
    vector<string> &split(const string &s, char delim, vector<string> &elems) {
        stringstream ss(s);
        string item;
        while(getline(ss, item, delim)) {
           elems.push_back(item);
        }
        return elems;
    }
    
    vector<string> split(const string &s, char delim) {
       vector<string> elems;
       return split(s, delim, elems);
    }
    
    
    bool isIPAddress(string  ipaddr){
    
        if (ipaddr.length()){
                vector<string> _ip=split(ipaddr,'.');
                if (_ip.size()==4){
                        for (int i=0; i < 4; i++){
                                for (int j=0; j < _ip[i].length(); j++)
                                        if (!isdigit(_ip[i][j])) return false;
                                if ((atoi(_ip[i].c_str()) < 0) || (atoi(_ip[i].c_str()) > 255)) return false;
                        }
                return true;
                }
        }
        return false;
     }
    
        14
  •  1
  •   user2314327    11 年前

    一些小的修复程序可以修复某些情况,如127..0.1、127.0.0..如果有以下情况,请删除空格:

    
    
    
        #include <iostream>
        #include <vector>
        #include <string>
        #include <sstream>
        #include <algorithm>
        #include <iterator>
        #include <stdio.h>
    
        using namespace std;
    
        vector split(char* str, char delimiter)
        {
            const string data(str);
            vector elements;
            string element;
            for(int i = 0; i  0) {//resolve problem: 127.0..1
                        elements.push_back(element);
                        element.clear();
                    }
                }
                else if (data[i] != ' ')
                {
                    element += data[i];
                }
    
            }
            if (element.length() > 0)//resolve problem: 127.0..1
                elements.push_back(element);
            return elements;
        }
    
        bool toInt(const string& str, int* result)
        {
            if (str.find_first_not_of("0123456789") != string::npos)
                return false;
    
            stringstream stream(str);
            stream >> *result; // Should probably check the return value here
            return true;
        }
    
        /** ipResult: the good ip address, e.g. spaces are removed */
        bool validate(char* ip, string *ipResult)
        {
            const static char delimiter = '.';
            const vector parts = split(ip, delimiter);
            *ipResult = "";
            if (parts.size() != 4)
                return NULL;
    
            for(int i = 0; i  255)
                    return NULL;
    
                if (i == 3) {
                    *ipResult += parts[i];
                } else {
                    *ipResult += (parts[i] +".");
                }
    
            }
            return true;
        }
    
        int main()
        {
            string ip;
            printf("right %d\n", validate("127.0.0.1", &ip));
            printf("good ip: %s\n", ip.c_str());
            printf("wrong %d\n", validate("127.0.0.-1", &ip));
            printf("good ip: %s\n", ip.c_str());
            printf("wrong %d\n", validate("127..0.1", &ip));
            printf("good ip: %s\n", ip.c_str());
            printf("wrong %d\n", validate("...0.1", &ip));
            printf("good ip: %s\n", ip.c_str());
            printf("wrong %d\n", validate("127.0.0.", &ip));
            printf("good ip: %s\n", ip.c_str());
            printf("right %d\n", validate("192.168.170.99", &ip));
            printf("good ip: %s\n", ip.c_str());
            printf("right %d\n", validate("127.0 .0  .1", &ip));
            printf("good ip: %s\n", ip.c_str());
            printf("\n");
    
            system("pause");
    
            return 0;
        }
    
    
        15
  •  1
  •   Kim Ninh    6 年前

    您可以这样编写自己的函数:

    bool isValidIPv4(const char *IPAddress)
    {
       unsigned char a,b,c,d;
       return sscanf(IPAddress,"%d.%d.%d.%d", &a, &b, &c, &d) == 4;
    }
    

    sscanf() sprintf() 在某些情况下非常有用。:)

        16
  •  0
  •   A. Smoliak    6 年前

    如果您希望接收常规格式的IP地址( 8.8.8.8 , 192.168.1.1 等 然后,我编写了以下扩展到Bjorn答案的代码:

    void validateIP(const std::string &IPv4_address)
    {
        boost::system::error_code error_code;
        auto raw_ipv4_address = boost::asio::ip::address::from_string(IPv4_address, error_code);
        if (error_code)
        {
            throw std::invalid_argument(error_code.message());
        }
    
        std::string raw_to_string_form = raw_ipv4_address.to_string();
        if (raw_to_string_form.compare(IPv4_address))
        {
            throw std::invalid_argument("Input IPv4 address is invalid");
        }
    }
    

    原因是,如果您传递IP,如8.88.8或12345 (十进制形式) ,比约恩的回答不会出错。 (至少在增压1.68的情况下) 我的代码将任何形式转换为Boost中的内部结构,然后将其转换回点分十进制格式,然后将其与收到的第一个IP进行比较,以查看它们是否相等,如果不相等,我们确定输入不是我们想要的方式。