简体   繁体   English

gethostbyname()返回带有负地址的结构

[英]gethostbyname() returns a struct with negative address

I'm writing a program that would check if a port on given url or ip is open or not. 我正在编写一个程序,该程序将检查给定url或ip上的端口是否打开。 In order to obtain the ip adress of given url, I'm using gethostbyname() . 为了获得给定URL的IP地址,我使用了gethostbyname() When trying to look up the address of localhost it returns the correct value, however, trying to look up the address of a remote host it usually fails and returns an ip address with negative numbers. 尝试查找localhost的地址时,它会返回正确的值,但是,尝试查找远程主机的地址时,它通常会失败并返回带有负数的ip地址。 For example: 例如:

/test.out google.com
ip: -40.58.-42.78

/test.out reddit.com
ip: -105.101.-127.-116

./test.out facebook.com
ip: 31.13.84.36

Weirdly, the last one works. 奇怪的是,最后一个作品。 Here's my code: 这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>

int main(int argc, char **argv)
{
    struct hostent *he;
    struct in_addr **addr_list;

    if ((he = gethostbyname(argv[1])) == NULL) {
        herror("gethostbyname");
        return 1;
    }

    printf("ip: ");
    for (int i = 0; i < he->h_length; i++) {
        printf("%d", he->h_addr_list[0][i]);
        if (i != he->h_length - 1) printf(".");
    }
    printf("\n");
}

Also, why is the type of h_addr_list char ** ? 另外,为什么h_addr_list char **的类型是? Shouldn't it be an integer, or even better an unsigned one? 它不应该是一个整数,甚至是一个无符号的整数吗?

The components of an IP address are unsigned bytes but, in a struct hostent they are stored as char (ie signed). IP地址的组成部分是无符号字节,但是在struct hostent主机中,它们被存储为char (即,有符号)。 This means the values 128 .. 255 are interpreted as negative numbers. 这意味着值128 .. 255被解释为负数。

You print them using the %d format that prints the values as signed because this is how it receives them. 您可以使用%d格式打印它们,该格式将按签名方式打印值,因为这是接收它们的方式。 Convert the values to unsigned char (or unsigned int if you prefer) when you pass them to printf() : 将值传递给printf()时,将值转换为unsigned char (如果愿意,则转换为unsigned int printf()

printf("%d", (unsigned char)he->h_addr_list[0][i]);

You can also use %u instead of %d (it treats as unsigned the values it receives), but you still need to convert the values to pass to it to unsigned 1 : 您也可以使用%u代替%d (它将接收到的值视为unsigned ),但是您仍然需要将值转换为传递给它的unsigned 1

printf("%u", (unsigned char)he->h_addr_list[0][i]);

Another option is to force printf() use only the least significant byte of the value it gets and print it as unsigned, using "%hhu" . 另一个选择是强制printf()仅使用它获取的值的最低有效字节,并使用"%hhu"将其打印为无符号。 However, this looks more like a hack than the correct solution. 但是,这看起来更像是hack,而不是正确的解决方案。


1 Without the conversion, because printf() is a variadic function , the values passed to it as arguments ( he->h_addr_list[0][i] ) are promoted from (signed) char to (signed) int . 1没有转换,因为printf()可变参数函数 ,作为参数传递给它的值( he->h_addr_list[0][i] )从(signed) char提升为(signed) int Using "%u" to print them produces very large numbers instead of negative numbers for the components that are larger than 127 . 使用"%u"打印它们会产生非常大的数字,而不是大于127的组件的负数。

This answer is specifically bout the type of h_addr_list . 这个答案特别是关于h_addr_list的类型。

In the minds of the ancient BSD programmers who invented gethostbyname , it was going to be used to look up all kinds of network addresses, not just IP addresses. 在发明了gethostbyname的古老BSD程序员的脑海中,它将被用来查找各种网络地址,而不仅仅是IP地址。 That's why it also has an h_addrtype . 这就是为什么它也有h_addrtype的原因。 The interpretation of h_addr_list[n] would be dependent on h_addrtype . h_addr_list[n]的解释将取决于h_addrtype For h_addrtype==AF_INET , an address is the 4-byte IP address format you're familiar with. 对于h_addrtype==AF_INET ,地址是您熟悉的4字节IP地址格式。 For other address types, it could be other things. 对于其他地址类型,可能是其他情况。

The char ** type of h_addr_list should be understood as "dynamically allocated array of opaque buffers". h_addr_listchar **类型应理解为“动态分配的不透明缓冲区数组”。 It might have been void ** but void hadn't been invented yet. 这可能是void ** ,但void还没有被发明出来。

As it turned out, IPv4 became the only network protocol anyone cared about, until IPv6 came along, and then it was decided to replace the host lookup interface entirely (see getaddrinfo ). 事实证明,在IPv6出现之前,IPv4成为任何人关心的唯一网络协议,然后决定完全替换主机查找接口(请参阅getaddrinfo )。 So there have been few opportunities to see a non- AF_INET h_addrtype in the wild. 因此,几乎没有机会在野外看到非AF_INET h_addrtype

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM