我正在努力使自己熟悉网络BSD。我理解提交给BSD的多字节数据(如地址和端口)必须是网络字节顺序,我们应该使用htonl()和htonl()这样的转换函数来完成这个任务。这段代码片段显示:
#define IP_ADDRESS(a, b, c, d) ((((uint32_t)a) << 24) | (((uint32_t)b) << 16) | (((uint32_t)c) << 8) | ((uint32_t)d))
/* Set server port in BSD format */
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(IP_ADDRESS(192,168,1,1));
serverAddr.sin_port = htons(21);
/* Connect to server */
status = connect(H->bsdSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
现在,我正在尝试使用getaddrinfo(),以便从服务器名中检索地址信息。我尝试了以下代码:
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
getaddrinfo( "srvdc01", "21", &hints, &addr_list );
if (addr_list != NULL)
{
ctx->fd = (int) socket( addr_list->ai_family, addr_list->ai_socktype,
addr_list->ai_protocol );
if (ctx->fd >= 0)
status = connect( ctx->fd, addr_list->ai_addr, addr_list->ai_addrlen );
}
我原以为getaddrinfo()返回的地址将按网络字节顺序排列,这样就可以直接将其输入connect()函数。不幸的是,这不适用于我使用的库,因为最终的connect正在恢复地址字节(我使用Wireshark来调查这个问题)。
是否允许安全地使用getaddrinfo()返回的地址来输入套接字()和connect()调用?
谢谢你,法兰克
===更新===
谢谢各位的评论。我可以再澄清一点。我运行了以下代码片段,结果如下:
struct addrinfo hints, *addr_list, *cur;
struct sockaddr_in addr_in;
memset(&addr_in, 0, sizeof(addr_in));
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(21);
addr_in.sin_addr.s_addr = htonl(0xC0A80101UL); // 192.168.1.1
myprintf("%08x\n", addr_in.sin_addr.s_addr);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if( getaddrinfo( "srvdc01", "21", &hints, &addr_list ) == 0 )
{
for( cur = addr_list; cur != NULL; cur = cur->ai_next )
{
ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype,
cur->ai_protocol );
if( ctx->fd >= 0 )
{
myprintf("%08x\n", ((struct sockaddr_in *)cur->ai_addr)->sin_addr.s_addr);
}
}
}
freeaddrinfo( addr_list );
第一个printf输出(在htonl之后)提供c0a80101,而第二个输出(在套接字创建后)提供0101a8c0。这是令人惊讶的,因为在我的小endian平台上,我希望htonl()调用能够以网络字节顺序交换字节。
在查看了我们的嵌入式网络库(第三方商业库)的文档之后,我们可以发现,它们提供的BSD API实际上是(相当)有限的包装器,它位于特定于供应商的网络库API之上。我们注意到,它们的库总是使用本机系统endianness,所以它们的htonl()函数总是一个虚拟调用,什么也不做。
现在,查看Martin . http://pubs.opengroup.org/onlinepubs/009695399/functions/freeaddrinfo.html提供的链接,我同意他的观点,即getaddrinfo()应该返回一个适合于调用connect()的地址信息,而这个嵌入式库显然并非如此。
发布于 2017-07-24 17:45:10
getaddrinfo()
的POSIX文档指出:
在成功返回getaddrinfo()后,res指向的位置将引用addrinfo结构的链接列表,每个结构都应指定一个套接字地址和信息,用于创建使用该套接字地址的套接字。列表应包括至少一个addrinfo结构。每个结构的ai_next字段包含指向列表上下一个结构的指针,如果它是列表上的最后一个结构,则为空指针。列表中的每个结构都应该包括用于调用socket()函数的值,以及用于connect()函数的套接字地址,或者如果指定了AI_PASSIVE标志,则用于绑定()函数。字段ai_family、ai_socktype和ai_protocol应可用作套接字()函数的参数,以创建适合与返回地址一起使用的套接字。根据connect()或bind()函数的参数,ai_addr和ai_addrlen字段可以使用这样的套接字。
这意味着-在符合POSIX的系统上,ai_addr
中的IP地址和端口号是按网络字节顺序排列的,正如connect()
函数所期望的那样。
https://stackoverflow.com/questions/45281238
复制相似问题