前言:
眼前同学们对“inet_ntop源码”大约比较重视,兄弟们都需要剖析一些“inet_ntop源码”的相关文章。那么小编在网摘上汇集了一些有关“inet_ntop源码””的相关内容,希望兄弟们能喜欢,朋友们快快来学习一下吧!简介
inet_pton的作用是将可读的IP地址(ipv4和ipv6均支持)字符串转换成网络序的函数,此函数的实现不在编译器中、也不在操作系统源码中,在C运行库的代码中实现。本文介绍的是Linux的C运行库:glibc对inet_pton函数的实现。
怎么找到glibc的inet_pton
fh@Feihu-3 glibc-2.34 % grep -nwr 'inet_pton' ./ | grep -nw 'weak_alias'7:.//resolv/inet_pton.c:72:weak_alias (__inet_pton, inet_pton)fh@Feihu-3 glibc-2.34 %
fh@Feihu-3 glibc-2.34 % vim include/libc-symbols.h
里面涉及到强引用和弱引用,请自行查阅相关资料。
接口源码实现
#include <string.h>#include <stdio.h>#include <nameser.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.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 = 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 (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;}static int 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);}
版权声明:
本站文章均来自互联网搜集,如有侵犯您的权益,请联系我们删除,谢谢。
标签: #inet_ntop源码