inet_pton的作用是将可读的IP地址(ipv4和ipv6均支持)字符串转换成网络序的函数
main.cpp
#include <Windows.h> #include <iostream> #include "my_net_pton.h" using namespace std; int main() { cout << "hello" << endl; int lRet = 0; UINT32 remote_address; lRet = my_pton(2, "192.168.6.38", &remote_address); cout << "remote_address:" << remote_address; lRet = my_pton(2, "193.168.6.38", &remote_address); cout << "remote_address:" << remote_address; return 0; }
my_net_pton.h
#ifndef MY_NET_PTON_H #define MY_NET_PTON_H #ifdef __cplusplus extern "C" { #endif #define NS_INT16SZ 2 #define NS_INADDRSZ 4 #define NS_IN6ADDRSZ 16 int my_pton(int af, const char* src, void* dst); #ifdef __cplusplus } #endif #endif
my_net_pton.c
#include <ntdef.h> #include <inaddr.h> #include <in6addr.h> #include "my_net_pton.h" #include <common/my_wsa.h> // ipv4是4个字节,xxx.yyy.mmm.nnn // 注意:每个八位组第一个不能为0 // 每个八位组值不能大于255 // 只能有4个八位组 // 整个ip字符串中只能有数字和'.'符号 // dst的结构体不需要理会,只需要知道dst为接收内存且长度只能是4字节,其他随意 static int inet_pton4(const char *src, const char *end, unsigned char *dst) { int saw_digit; // 每个八位组是否遇到数字标记,新的八位组将会清除标记 int octets; // 八位组的个数,ip地址合法,则为4个 int ch; // 遍历字符串,每次获得的字符 // NS_INADDRSZ长度是4个字节, 宏定义在nameser.h中 // 注意tmp不是字符串,仅仅是用来存放4个字节的数据,无'\0' unsigned char tmp[NS_INADDRSZ]; unsigned char *tp; // tp指的是八位组 saw_digit = 0; octets = 0; *(tp = tmp) = 0; // *tp = 0;初始化必须为0,计算数值的时候会有依赖 // 本函数实际上是转换成网络序的,所以方向是src -> end // 如果仅仅转换成二进制,方向是end -> src while (src < end) { ch = *src++; // 得到获得的ASCII值,src指向下一个字符 if (ch >= '0' && ch <= '9') { // 八位组迭代,比如192.168.8.217 // 以192为例: // 0 -> 0 * 10 + 1 = 1 -> 1 * 10 + 9 = 19 -> 19 * 10 + 2 = 192 // 在将192赋值到tmp的第一个字节上(第一个八位组) unsigned int new = *tp * 10 + (ch - '0'); // 八位组中不能以0开头,比如192.168.08.217是错误的 if (saw_digit && *tp == 0) return 0; // 某一个八位组值不能超过255 if (new > 255) return 0; // 八位组赋值 *tp = (unsigned char)new; // 一般是在遇到'.'的时候,(! saw_digit)为0 // 而在'.'之后的第一个数字置为1 // 统计八位组的数目,由于在运行中,所以值不得超过4 if (! saw_digit) { if (++octets > 4) return 0; saw_digit = 1; } } else if (ch == '.' && saw_digit) { if (octets == 4) return 0; // 下一个八位组赋值,必须为0,方面迭代 // saw_digit标记为未遇到数值 *++tp = 0; saw_digit = 0; } else return 0; // 其他字符,直接返回错误 } if (octets < 4) return 0; memcpy (dst, tmp, NS_INADDRSZ); return 1; } static int hex_digit_value(char ch) { if ('0' <= ch && ch <= '9') return ch - '0'; if ('a' <= ch && ch <= 'f') return ch - 'a' + 10; if ('A' <= ch && ch <= 'F') return ch - 'A' + 10; return -1; } static int inet_pton6(const char *src, const char *src_endp, unsigned char *dst) { unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; const char *curtok; int ch; size_t xdigits_seen; /* Number of hex digits since colon. */ unsigned int val; tp = memset (tmp, '\0', NS_IN6ADDRSZ); endp = tp + NS_IN6ADDRSZ; colonp = NULL; /* Leading :: requires some special handling. */ if (src == src_endp) return 0; if (*src == ':') { ++src; if (src == src_endp || *src != ':') return 0; } curtok = src; xdigits_seen = 0; val = 0; while (src < src_endp) { ch = *src++; int digit = hex_digit_value ((char)ch); if (digit >= 0) { if (xdigits_seen == 4) return 0; val <<= 4; val |= digit; if (val > 0xffff) return 0; ++xdigits_seen; continue; } if (ch == ':') { curtok = src; if (xdigits_seen == 0) { if (colonp) return 0; colonp = tp; continue; } else if (src == src_endp) return 0; if (tp + NS_INT16SZ > endp) return 0; *tp++ = (unsigned char) (val >> 8) & 0xff; *tp++ = (unsigned char) val & 0xff; xdigits_seen = 0; val = 0; continue; } if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && inet_pton4 (curtok, src_endp, tp) > 0) { tp += NS_INADDRSZ; xdigits_seen = 0; break; /* '\0' was seen by inet_pton4. */ } return 0; } if (xdigits_seen > 0) { if (tp + NS_INT16SZ > endp) return 0; *tp++ = (unsigned char) (val >> 8) & 0xff; *tp++ = (unsigned char) val & 0xff; } if (colonp != NULL) { /* Replace :: with zeros. */ if (tp == endp) /* :: would expand to a zero-width field. */ return 0; size_t n = tp - colonp; memmove (endp - n, colonp, n); memset (colonp, 0, endp - n - colonp); tp = endp; } if (tp != endp) return 0; memcpy (dst, tmp, NS_IN6ADDRSZ); return 1; } static int _inet_pton_length(int af, const char *src, size_t srclen, void *dst) { switch (af) { case AF_INET: return inet_pton4(src, src + srclen, dst); case AF_INET6: return inet_pton6(src, src + srclen, dst); default: //printf("invalid AF, af: %d.\n", af); return -1; } return -1; } int my_pton(int af, const char *src, void *dst) { return _inet_pton_length(af, src, strlen(src), dst); } //void AddrConvertTest(void) //{ // char szIpv4[INET_ADDRSTRLEN] = "192.168.8.217"; // //char szIpv4[INET_ADDRSTRLEN] = "192.168.10.1"; // unsigned int ulIpv4 = 3232237785; // printf("ip: %s, dec: %u, little-endian-hex: %#x, big-endian-hex: %#x\n", szIpv4, ulIpv4, ulIpv4, htonl(ulIpv4)); // // struct in_addr stIpv4Addr = {0}; // int lRet = 0; // lRet = pton(AF_INET, szIpv4, &stIpv4Addr); // printf("pton ret: %d, ip: %s, s_addr: %#x.\n", lRet, szIpv4, stIpv4Addr.s_addr); // return; //} //void AddrConvertLibcTest(void) //{ // char szStrIp[] = "192.168.8.217"; // unsigned int ulIp = 3232237785; // printf("ip: %s, dec: %u, little-endian-hex: %#x, big-endian-hex: %#x\n", szStrIp, ulIp, ulIp, htonl(ulIp)); // char *pcTmp = NULL; // int lRet = 0; // struct in_addr stInAddr = {0}; // stInAddr.s_addr = inet_addr("192.168.8.217"); // pcTmp = inet_ntoa(stInAddr); // printf("inet_ntoa, ret: %s, s_addr: %#x.\n", pcTmp, stInAddr.s_addr); // // /** inet_addr 处理255.255.255.255以及错误的ip返回的结果为0xffffffff // */ // stInAddr.s_addr = inet_addr("259.255.255.255"); // printf("inet_addr s_addr: %#x.\n", stInAddr.s_addr); // // char szIp[INET_ADDRSTRLEN] = "192.168.8.217"; // struct in_addr stOutAddr = {0}; // lRet = inet_aton(szIp, &stOutAddr); // printf("inet_aton ret: %d, ip: %s, s_addr: %#x.\n", lRet, szIp, stOutAddr.s_addr); // // struct in_addr stAddr2 = {0}; // char szIp2[INET_ADDRSTRLEN] = "192.168.8.217"; // // 文本字符串格式转换成网络字节序的二进制地址 // lRet = inet_pton(AF_INET, szIp2, &stAddr2); // int ipv4StructSize = sizeof(struct in_addr); // printf("inet_pton ret: %d, ip: %s, s_addr: %#x.\n", lRet, szIp2, stAddr2.s_addr); // // const char *pcTmp2 = NULL; // memset(szIp2, 0, sizeof(szIp2)); // // 网络字节序的二进制地址转换成文本字符串格式 // pcTmp2 = inet_ntop(AF_INET, &stAddr2, szIp2, INET_ADDRSTRLEN); // printf("inet_ntop ret: %s, ip: %s.\n", pcTmp2, szIp2); //}