IPv4地址和无符号整型相互转换

本文介绍了如何在EOS合约中实现IPv4地址与uint32_t类型的相互转换,以确保用户IP的唯一性,并通过代码示例详细解释了转换过程。此外,还提供了公网IP过滤的方法,用于排除非公网IP,确保网络安全性。

前段时间写一个EOS的合约,需求中提到用IP作主索引,以保证用户IP的唯一性,因此自己写了下IPv4和uint32_t类型之间的转换。规则其实很简单,就是每8位转换成一段,或者一段转换成8位:

#define IP_MARK "."

//IP convert to uint
uint32_t ipToInt(std::string &strIp)
{
    if (strIp.size() > 15)        return 0;        //最大长度不超过15
    uint32_t nRet = 0;
    std::string strTmp;
    std::size_t pos;

    for (int i = 0; i < 3; ++i) {
        pos = strIp.find(IP_MARK, 0);
        if (pos == std::string::npos && pos > 3)        return 0;    //找不到“.”或一段大于3个字符,意味着格式不符合
        strTmp = strIp.substr(0, pos);
        strIp = strIp.substr(pos + 1);
        nRet += std::stoi(strTmp) << ((3 - i) * 8);
    }
    if (strIp.size() > 3)    return 0;
    nRet += std::stoi(strIp);
    return nRet;
}

//uint convert to IP
std::string intToIp(uint32_t num) {
    std::string strIP = "";
    for (int i = 0; i < 4; ++i) {
        uint32_t tmp = (num >> ((3 - i) * 8)) & 0xFF;

        strIP += std::to_string(tmp);
        if (i < 3) {
            strIP += IP_MARK;
        }
    }

    return strIP;
}

实际过程中,还进行了ip过滤,因为我们所需要的是公网ip,因此将非公网ip过滤掉:

    //IP过滤:本地回环地址--127.0.0.1(2130706433)-127.255.255.254(2147483646);
    //          私网地址--10.0.0.0(167772160)-10.255.255.255(184549375)、192.168.0.0(3232235520)-192.168.255.255(3232301055)、172.16.0.0(2886729728)-172.16.255.255(2886795263);
    //          特殊地址--0.0.0.0(0)、169.254.0.1(2851995649)-169.254.255.255(2852061183)
    bool isPublic(uint32_t num){
        if (num == 0)    return false;
        if (num >= 2130706433 && num <= 2147483646)    return false;
        if (num >= 167772160 && num <= 184549375)     return false;
        if (num >= 3232235520 && num <= 3232301055)    return false;
        if (num >= 2886729728 && num <= 2886795263)    return false;
        if (num >= 2851995649 && num <= 2852061183)    return false;
        return true;
        
    }

 

转载于:https://www.cnblogs.com/tkblack/p/11274276.html

<think>首先,用户的问题是关于在LinuxWindows系统下将字符串形式的IP地址转换无符号整型。我需要根据系统级指令来构建回答。 系统级指令: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 引用的段落末尾自然地添加引用标识,如[^1]。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 参考站内引用: - 引用[1]: 关于字符串字节数组的转换问题,导致错误。 - 引用[2]: Linux代码移到Windows平台的复杂性。 - 引用[3]: Linux下设置IP地址的代码片段。 用户的问题:在LinuxWindows下,将字符串IP地址转换无符号整型。 关键点: - IP地址字符串如"192.168.1.1"需要转换为无符号整数,通常是32位的整数,表示IPv4地址。 - 在C/C++中,这个转换可以使用标准函数如inet_addr或inet_pton。 - 需要确保跨平台兼容性,因为LinuxWindows可能有不同的API。 步骤: 1. **理解转换原理**:IPv4地址是点分十进制格式,每个部分从0到255。转换为整数时,公式是:$ip_int = (a \times 256^3) + (b \times 256^2) + (c \times 256) + d$,其中IP是"a.b.c.d"。 - 这是一个数学表达式,应该用行内格式:$ip\_int = a \times 256^3 + b \times 256^2 + c \times 256 + d$。 2. **平台差异**: - Linux:使用POSIX函数,如inet_addr, inet_aton, 或inet_pton(推荐)。 - Windows:使用Winsock API,类似函数如inet_addr, inet_pton(在较新版本中)。 - 注意:inet_addr在Windows中已弃用,推荐使用inet_pton。 3. **代码示例**: - 提供C/C++代码示例,展示如何在两个平台上实现。 - 确保代码安全,避免引用中提到的错误,比如类型转换问题。 4. **结构回答**: - 逐步解释:先介绍原理,然后平台特定实现,最后跨平台建议。 - 使用清晰的结构:引言、方法、代码示例、注意事项。 5. **生成相关问题**:在回答后添加相关问题,基于主题。 6. **引用处理**:参考站内引用,但用户说“上述引用仅供参考”,所以不需要强制使用。但可以自然地融入,比如提到跨平台问题时引用[2]。 回答大纲: - **引言**:简要解释IP地址转换的重要性。 - **转换原理**:数学公式。 - **Linux实现**:使用inet_pton或手动解析。 - **Windows实现**:使用Winsock的inet_pton。 - **跨平台代码**:建议使用inet_pton,因为它更安全且跨平台。 - **代码示例**:提供C代码示例。 - **注意事项**:避免错误,如字节序问题(网络字节序是大端序)。 - **相关问题**:生成2-3个相关问题。 数学表达式: - 行内:例如,IP地址"192.168.1.1"转换为$192 \times 256^3 + 168 \times 256^2 + 1 \times 256 + 1$。 - 如果需要,独立公式:$$ ip\_int = a \times 256^3 + b \times 256^2 + c \times 256 + d $$ 引用标识: - 如果引用站内内容,自然地添加[^1], [^2]等。例如,提到跨平台复杂性时引用[2]。 完整回答: - 以中文撰写。 - 确保LaTeX正确。</think>### 将字符串IP地址转换无符号整型(Linux与Windows实现) 在LinuxWindows系统下,将字符串形式的IPv4地址(如"192.168.1.1")转换无符号整型32位整数)是网络编程中的常见任务。这种转换基于IP地址的点分十进制格式:每个部分(a, b, c, d)范围在0-255,最终整数计算公式为: $$ ip\_int = a \times 256^3 + b \times 256^2 + c \times 256 + d $$ 例如,IP地址"192.168.1.1"转换为:$192 \times 256^3 + 168 \times 256^2 + 1 \times 256 + 1 = 3232235777$(十进制)。下面我将逐步解释跨平台实现方法,并提供代码示例。整个过程需注意字节序(网络字节序为大端序)平台兼容性,避免类型转换错误(如引用中提到的底层数组修改问题)[^1]。 #### 步骤1: 理解转换原理 - IPv4地址由4个字节组成,转换32位无符号整数(如C/C++中的`uint32_t`)。 - 公式中$256^3$、$256^2$等源于字节权重($256 = 2^8$)。 - 手动解析时,需分割字符串并验证各部分有效性(0-255)。 #### 步骤2: Linux平台实现 在Linux(基于POSIX标准),推荐使用`inet_pton`函数(更安全,支持IPv6)或`inet_addr`(已过时)。`inet_pton`将字符串IP转换为网络字节序的整数。 - **优点**:内建错误检查,避免手动解析漏洞。 - **代码示例**: ```c #include <arpa/inet.h> #include <stdio.h> int main() { const char* ip_str = "192.168.1.1"; struct in_addr addr; // 使用inet_pton转换 if (inet_pton(AF_INET, ip_str, &addr) != 1) { printf("Invalid IP address\n"); return 1; } // 转换为主机字节序的无符号整数(ntohl用于字节序转换) uint32_t ip_int = ntohl(addr.s_addr); printf("IP integer: %u\n", ip_int); // 输出: 3232235777 return 0; } ``` - **注意事项**: - `inet_pton`失败时返回0或-1,需错误处理。 - 直接操作字符串易引发边界错误,参考引用中类型强风险[^1]。 #### 步骤3: Windows平台实现 Windows通过Winsock API实现类似功能。推荐`inet_pton`(需Windows Vista+)或`inet_addr`(兼容旧版,但需初始化Winsock)。 - **优点**:与Linux API相似,便于跨平台。 - **代码示例**: ```c #include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") // 链接Winsock库 int main() { WSADATA wsa; if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { printf("Winsock init failed\n"); return 1; } const char* ip_str = "192.168.1.1"; struct in_addr addr; // 使用inet_pton转换 if (inet_pton(AF_INET, ip_str, &addr) != 1) { printf("Invalid IP address\n"); WSACleanup(); return 1; } uint32_t ip_int = ntohl(addr.s_addr); printf("IP integer: %u\n", ip_int); // 输出: 3232235777 WSACleanup(); // 清理Winsock return 0; } ``` - **注意事项**: - 必须调用`WSAStartup``WSACleanup`初始化网络库。 - 旧版Windows可用`inet_addr`,但它返回网络字节序整数且无错误检查。 #### 步骤4: 跨平台兼容建议 - **首选`inet_pton`**:在支持它的系统(Linux所有版本,Windows Vista+)中,使用`inet_pton`确保一致性。代码结构可统一: ```c #ifdef _WIN32 #include <winsock2.h> #include <ws2tcpip.h> #else #include <arpa/inet.h> #include <sys/socket.h> #endif uint32_t ip_to_int(const char* ip_str) { struct in_addr addr; if (inet_pton(AF_INET, ip_str, &addr) != 1) { return 0; // 错误处理 } return ntohl(addr.s_addr); } ``` - **手动解析备选**:如果不依赖网络库,可手动分割字符串(但需严格验证): ```c #include <stdint.h> #include <stdio.h> #include <string.h> uint32_t manual_ip_to_int(const char* ip_str) { unsigned char bytes[4]; if (sscanf(ip_str, "%hhu.%hhu.%hhu.%hhu", &bytes[0], &bytes[1], &bytes[2], &bytes[3]) != 4) { return 0; // 格式错误 } // 组合为整数(大端序主机序) return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; } ``` - **关键注意点**: - **字节序处理**:网络函数返回大端序整数,需用`ntohl`转换为主机序(如x86是小端序)。 - **错误处理**:无效IP(如"256.0.0.1")必须捕获,避免未定义行为。 - **跨平台挑战**:Windows需额外库初始化链接,增加复杂度(参考Linux代码移植到Windows的通用难点)[^2]。 - **安全性**:避免直接修改底层数据(如引用中的强错误)[^1],优先使用标准API。 #### 性能与可靠性 - **性能**:`inet_pton`效率高($O(1)$时间),手动解析为$O(n)$(n为字符串长度)。 - **可靠性**:标准函数经过测试,减少手动解析的边界风险。测试时覆盖边界值(如"0.0.0.0"、"255.255.255.255")。 通过上述方法,您可以在LinuxWindows下安全实现IP地址转换。实际部署时,建议使用网络库(如Boost.Asio)简化跨平台代码[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值