我有一段代码连接到本地石墨(实际上是运行在本地主机上的nc -l -p 2023
):
getCarbonAddr :: Config -> IO SockAddr
getCarbonAddr cfg = do
let host = (graphiteHost . graphiteConfig) cfg
let port = (graphitePort . graphiteConfig) cfg
-- addrInfos <- getAddrInfo (Just defaultHints)
addrInfos <- getAddrInfo Nothing
(Just host)
(Just (show port))
putStrLn $ "addrInfos: " ++ show addrInfos
c <- case addrInfos of
(addrInfo : _) -> return (addrAddress addrInfo)
_ -> unsupportedAddressError host
return c
where
unsupportedAddressError h = ioError $ userError $
"unsupported address: " ++ h
主机和端口的配置值分别为"localhost“和2023。升级到约塞米蒂后,当我在OS X上运行这个程序时--我看到了以下崩溃:
addrInfos: [AddrInfo {addrFlags = [], addrFamily = AF_INET6, addrSocketType = Datagram, addrProtocol = 17, addrAddress = [::1]:2023, addrCanonName = Nothing},AddrInfo {addrFlags = [], addrFamily = AF_INET6, addrSocketType = Stream, addrProtocol = 6, addrAddress = [::1]:2023, addrCanonName = Nothing},AddrInfo {addrFlags = [], addrFamily = AF_INET, addrSocketType = Datagram, addrProtocol = 17, addrAddress = 127.0.0.1:2023, addrCanonName = Nothing},AddrInfo {addrFlags = [], addrFamily = AF_INET, addrSocketType = Stream, addrProtocol = 6, addrAddress = 127.0.0.1:2023, addrCanonName = Nothing},AddrInfo {addrFlags = [], addrFamily = AF_INET6, addrSocketType = Datagram, addrProtocol = 17, addrAddress = [fe80::1%lo0]:2023, addrCanonName = Nothing},AddrInfo {addrFlags = [], addrFamily = AF_INET6, addrSocketType = Stream, addrProtocol = 6, addrAddress = [fe80::1%lo0]:2023, addrCanonName = Nothing}]
LocalJob: connect: unsupported operation (Address family not supported by protocol family)
这对我来说很奇怪,所以我决定运行这个C程序(谷歌搜索"getaddrinfo“示例,更改主机名和端口,添加ai_family打印):
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#ifndef NI_MAXHOST
#define NI_MAXHOST 1025
#endif
int main(void)
{
struct addrinfo *result;
struct addrinfo *res;
int error;
/* resolve the domain name into a list of addresses */
error = getaddrinfo("localhost", "2023", NULL, &result);
if (error != 0)
{
fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
return EXIT_FAILURE;
}
/* loop over all returned results and do inverse lookup */
for (res = result; res != NULL; res = res->ai_next)
{
char hostname[NI_MAXHOST] = "";
error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0);
if (error != 0)
{
fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error));
continue;
}
if (*hostname != '\0')
printf("hostname: %s. ai_family: %i\n", hostname, res->ai_family);
}
freeaddrinfo(result);
return EXIT_SUCCESS;
}
在启动它之后,我看到了这个输出:
➜ getaddrinfotest ./main
hostname: localhost. ai_family: 30
hostname: localhost. ai_family: 30
hostname: localhost. ai_family: 2
hostname: localhost. ai_family: 2
hostname: localhost. ai_family: 30
hostname: localhost. ai_family: 30
因此,ai_family 30似乎是一件奇怪的事情。正如我从socket.h源中了解到的,它是AF_TIPC协议,这是我以前从未听说过的一件非常罕见的事情。我还打开了haskell的packFamily源,惊讶地发现它没有处理30的值(不知道AF_TIPC)。
我要问的问题是:现在最好做什么?我猜对了吗?haskell应该更好地处理未知的ai家族吗? //谢谢!
更新:我通过提示使用ipv4解决了一个问题:
addrInfos <- getAddrInfo (Just (defaultHints { addrFamily=AF_INET }))
(Just host)
(Just (show port))
但我仍然不知道如何“以正确的方式”解决这一问题。
发布于 2014-10-27 14:00:03
默认情况下,getaddrinfo
(及其Haskell绑定getAddrInfo
)返回一个可包含IPv4地址、IPv6地址或两者混合的addrinfo链接列表。不幸的是,套接字函数不允许将IPv4套接字连接到IPv6地址,因此在迭代地址列表时,需要创建正确类型的套接字:
addrinfos <- getAddrInfo Nothing (Just hostname) (Just (show port))
let first = head addrinfos
sock <- socket (addrFamily first) Stream defaultProtocol
connect sock (addrAddress first)
注意如何将(addrFamily first)
传递给socket
函数,以便在正确的协议系列中创建套接字。
在实际代码中,您需要迭代列表addrinfos
,并尝试连接到getAddrInfo
返回的所有地址。当您这样做时,不要忘记关闭连接失败的套接字。
https://stackoverflow.com/questions/26588469
复制相似问题