是否有一种聪明/棘手的方法来分析表示IP地址的字符串是否有效并识别其版本,以便能够将其转换为适当的结构,只需使用UNIX API?
我不想使用正则表达式,不需要为其他库添加依赖关系。
我的第一个方法是:
in_addr addr;
memset( &addr, 0, sizeof( in_addr ) );
// try to convert from standard numbers-and-dots notation into binary data
if( 0 != inet_aton( sIPAddress.c_str(), &addr ) )
{
return Socket::enIPv4; // valid IPv4
}
in6_addr addr6;
memset( &addr6, 0, sizeof( in6_addr ) );
if( inet_pton( AF_INET6, sIPAddress.c_str(), &addr6 ) > 0 )
{
return Socket::enIPv6; // valid IPv6
}
return Socket::enUnknown;
这里的问题是,如果我传递像1
这样的字符串,它就会成功转换为IPv4。像11111
这样的字符串也会转换为IPv4。通过文档:
如果地址有效,则inet_aton()返回非零值,否则返回零。
显然,这个函数不仅可以识别XXX.XXX.XXX.XXX
格式,还可以更内部地执行某些操作。
当然,我可以编写自己的函数(实际上它会很有趣),通过分析字符串,但我想使用已经存在并经过测试的函数。是否有可能或我应该自己编写?
答案 0 :(得分:4)
根据manual page,"a"
,"a.b"
和"a.b.c"
等字符串都是inet_aton
的有效地址。如果您只想要“正常”点分十进制,请对这些地址使用inet_pton
。
答案 1 :(得分:3)
如果您对Boost图书馆开放,请查看Boost Asio
boost::asio::ip::address
类非常擅长解析IPv6和IPv4地址,并试图提出用于验证输入的正则表达式等。它也是跨平台的。
#include <boost/asio.hpp>
#include <boost/assert.hpp>
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[]){
std::string ipv4("192.168.1.1");
std::string ipv6("::1");
std::string notIP("1");
boost::asio::ip::address ipv4Addr = boost::asio::ip::address::from_string(ipv4);
BOOST_ASSERT(ipv4Addr.is_v4() == true);
boost::asio::ip::address ipv6Addr = boost::asio::ip::address::from_string(ipv6);
BOOST_ASSERT(ipv6Addr.is_v6() == true);
boost::asio::ip::address badAddr;
try{
badAddr = boost::asio::ip::address::from_string(notIP);
}
catch(const std::exception& e){
std::cout << "Bad Address: " << e.what() << std::endl;
}
return 0;
}
打印:
$ g++ -Wall -I/usr/local/boost-1.47.0/include/ -L/usr/local/boost-1.47.0/lib -o ./asioTestIP ./asioTestIP.cpp -lboost_system
$ ./asioTestIP
Bad Address: Invalid argument
答案 2 :(得分:0)
这应该有效:
#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
void printError(const std::string& errStr) {
std::cerr << errStr << std::endl;
}
bool checkAddress(const std::string& address) {
std::vector<std::string> arr;
int k = 0;
arr.push_back(std::string());
for (std::string::const_iterator i = address.begin(); i != address.end(); ++i) {
if (*i == '.') {
++k;
arr.push_back(std::string());
if (k == 4) {
printError("too many '.'");
}
continue;
}
if (*i >= '0' && *i <= '9') {
arr[k] += *i;
} else {
printError("wrong character");
return false;
}
if (arr[k].size() > 3) {
printError("size exceeded");
return false;
}
}
if (k != 3) {
printError("not enough '.'");
return false;
}
for (int i = 0; i != 4; ++i) {
const char* nPtr = arr[i].c_str();
char* endPtr = 0;
const unsigned long a = ::strtoul(nPtr, &endPtr, 10);
if (nPtr == endPtr) {
printError("invalid numeric input");
return false;
}
if (a > 255) {
printError("out of range");
return false;
}
}
return true;
}
int main(int argc, char* argv[]) {
if (argc < 2) {
return -1;
}
std::string address = argv[1];
if (checkAddress(address)) {
std::cout << "address ok" << std::endl;
} else {
std::cout << "bad address" << std::endl;
}
return 0;
}
答案 3 :(得分:0)
我在一个项目中解决了这个问题。首先,我制作了ip-addresses的EBNF,然后创建了算法。它的工作原理很好,并没有使用任何外国图书馆。 你必须调用方法CheckWholeIp并将其交给ip-string(例如:CheckWholeIp(&#34; 127.0.0.1&#34;)。如果它适合ipv4方案,它将返回int 0,如果它适合ipv4方案则返回0它不是。但值得注意的是,127.055.008.001这样的地址也会被接受。没有必要过滤前面的零。 让我知道你的想法;)
cpp文件:
#include "CheckIp.h"
CheckIp::CheckIp()
{
}
int CheckIp::CheckWholeIp(string s)
{
int size = s.size();
int psum = 0;
//check amount of points
for (int i = 0; i <= size; i++) {
if (s[i] == '.')psum++;
}
if (psum != 3)return 1;
//write stringblocks
string sbl0 = "";
string sbl1 = "";
string sbl2 = "";
string sbl3 = "";
int ii = 0;
while (s[ii] != '.') {
sbl0 = sbl0 + s[ii];
ii++;
}
ii++;
while (s[ii] != '.') {
sbl1 = sbl1 + s[ii];
ii++;
}
ii++;
while (s[ii] != '.') {
sbl2 = sbl2 + s[ii];
ii++;
}
ii++;
while (s[ii] != NULL) {
sbl3 = sbl3 + s[ii];
ii++;
}
//checking the blocks
if (CheckBlock(sbl0) == 1 | CheckBlock(sbl1) == 1 | CheckBlock(sbl2) == 1 | CheckBlock(sbl3) == 1) return 1;
return 0;
}
int CheckIp::CheckBlock(string s)
{
int sizeb = s.size();
//checking size of block
if (sizeb > 3) return 1;
string ss;
for (int i = 0; i < sizeb; i++) {
ss = s[i];
if (CheckNumber(ss) == 1) return 1;
}
return 0;
}
int CheckIp::CheckNumber(string s)
{
if (s == "0" | s == "1" | s == "2" | s == "3" | s == "4" | s == "5" | s == "6" | s == "7" | s == "8" | s == "9") {
return 0;
}
else {
return 1;
}
}
部首:
#pragma once
#include <string>
using namespace std;
ref class CheckIp
{
public:
CheckIp();
static int CheckWholeIp(string s);
private: static int CheckBlock(string s);
static int CheckNumber(string s);
};