我想将IP地址转换为二进制文件,以便将它们存储在MySQL DB中。 在线搜索说这是存储地址的最有效方式,因为ipv4适合4个字节,ipv6适合16个字节(What is the ideal datatype to store IP address in a mysql table?)。
现在,似乎常见的方法是使用inet_pton()函数,该函数说:" inet_pton - 将IPv4和IPv6地址从文本转换为二进制形式" (http://man7.org/linux/man-pages/man3/inet_pton.3.html)
所以我的问题是二进制数存储在哪里?
我使用" sockaddr_in"大多数在线指南建议使用inet_pton结构,这就是结构的样子:
struct sockaddr_in {
short sin_family; // e.g. AF_INET
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct in_addr {
unsigned long s_addr; // load with inet_ntop()
};
我的代码基本上是:
#include <arpa/inet.h>
int main(int argc, const char *argv[]) {
if (argc >= 2) {
char *ip = malloc(strlen(argv[1]) + 1);
memcpy(ip, argv[1], strlen(argv[1]) + 1);
struct sockaddr_in sa;
char str[INET_ADDRSTRLEN];
// store this IP address in sa:
inet_pton(AF_INET, ip, &sa.sin_addr);
/* for verifying purposes, I'm trying to print the result
to make sure I get a binary number (obviously, "%d" should
not print a binary yet I do get an int result) */
printf("%d\n", sa.sin_addr.s_addr);
}
}
我得到的输出(使用127.0.0.1作为输入)是:16777343&lt; - 这看起来不像二进制数,如果它实际上是printf也不应该打印二进制数。如果inet_pton()将IP转换为二进制,那么该二进制文件在哪里。
如果可能,我更愿意提供一个解决方案,包括printf打印二进制文件以验证结果(但这只是个人偏好)。
我的问题不是关于如何将int转换为二进制,而是关于inet_pton函数输出。我希望在答案中包含一个将int转换为二进制的机制作为奖励,但这绝不是问题的主题 - 因此它与Print an int in binary representation using C不重复:@ {3}} Andre Kampling在评论中建议
答案 0 :(得分:2)
我得到的输出(使用127.0.0.1作为输入)是:16777343&lt; - 这似乎不是二进制数
如前所述,所有内容都存储在计算机中的“ binary ”中。 %d
的{{1}}转换说明符只是将位模式解释为数字。
如果有可能,我更愿意找到一个解决方案来包含打印二进制文件的printf以验证结果(但这只是个人偏好)。
printf()
中没有“二进制数”的转换说明符,因此您必须编写自己的实现。例如。对于printf()
,它看起来像这样:
int
“奇怪”宏用于可移植地确定#define IMAX_BITS(m) ((m) /((m)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \
+ (m)%0x3fffffffL /((m)%31+1)/31%31*5 + 4-12/((m)%31+3))
// use unsigned because we don't want to treat a sign bit specially
void print_binary(unsigned int i)
{
unsigned mask = 1 << (IMAX_BITS((unsigned)-1) - 1);
while (mask)
{
putchar(i & mask ? '1' : '0');
mask >>= 1;
}
}
中的位数,有关详细信息,请参阅this answer。
答案 1 :(得分:1)
[...]二进制文件在哪里?
inet_pton(AF_INET, ip, &sa.sin_addr);
获取ip
指向的内容,将其转换为IP地址的二进制表示形式,然后将结果存储在sa.sin_addr
的地址下。
sa.sin_addr
的类型为struct in_addr
,后者又定义为
struct in_addr {
unsigned long s_addr;
};
实际上只不过是unsigned long
。
unsigned long
(以及所有其他整数/浮点数据类型)按概念将其值存储为二进制。您无需验证此...; - )
因此,要将上述转换的结果存储到SQL数据库中,您需要一个能够存储至少unsigned long
的SQL列类型。
要将上述转换的结果传递给将其存储到数据库中的任何函数,请传递
sa.sin_addr
或
sa.sin_addr.s_addr
答案 2 :(得分:0)
为了支持IPv4和IPv6地址:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <arpa/inet.h>
// Convert IPv4 or IPv6 to 16-bytes binary
int ip_to_binary (const char *ip, void *binary_16_bytes)
{
struct sockaddr_in sa4;
struct sockaddr_in6 sa6;
if (inet_pton (AF_INET, ip, &sa4.sin_addr) == 1) {
// This is a valid IPv4 address - copy 4 bytes to the end of binary
memset (binary_16_bytes, 0, 12);
memcpy (binary_16_bytes + 12, &sa4.sin_addr, 4);
} else if (inet_pton (AF_INET6, ip, &sa6.sin6_addr) == 1) {
// This is a valid IPv6 address
memcpy (binary_16_bytes, &sa6.sin6_addr, 16);
} else {
// This is crap...
return -1;
}
return 0;
}
// Convert 16-bytes binary to IPv4 or IPv6 address
int binary_to_ip (const void *binary_16_bytes, char *buf, size_t buflen)
{
static uint8_t zero[16] = {0};
short family;
const void *sin_addr;
// If first 12 bytes (but not all 16 bytes) are zeroes, then treat it as IPv4 address
if (!memcmp (binary_16_bytes, zero, 12) && memcmp (binary_16_bytes, zero, 16)) {
family = AF_INET;
sin_addr = binary_16_bytes + 12;
} else {
family = AF_INET6;
sin_addr = binary_16_bytes;
}
if (inet_ntop (family, sin_addr, buf, buflen) != NULL) {
return 0;
} else {
return -1;
}
}
int main (int argc, char *argv[])
{
uint8_t binary[16];
if (argc >= 2) {
// IP address to binary
if (ip_to_binary (argv[1], binary) != 0) {
printf ("Invalid IP address!\n");
exit (1);
}
// Binary back to IP address
char buf[INET6_ADDRSTRLEN];
if (binary_to_ip (binary, buf, sizeof (buf)) == 0) {
printf ("IP address: %s\n", buf);
}
}
}
然后您可以通过执行以下操作将此缓冲区绑定到语句:(不确定,我还没有使用MySQL C API)
// ...
MYSQL_BIND bind;
unsigned long len = sizeof (binary);
bind.buffer_type = MYSQL_TYPE_BLOB;
bind.buffer = binary;
bind.buffer_length = len;
bind.is_null = 0;
bind.length = &len;
// ...