首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Haskell:不支持的操作(不受协议族支持的地址家族)

Haskell:不支持的操作(不受协议族支持的地址家族)
EN

Stack Overflow用户
提问于 2014-10-27 13:18:32
回答 1查看 1.3K关注 0票数 3

我有一段代码连接到本地石墨(实际上是运行在本地主机上的nc -l -p 2023 ):

代码语言:javascript
运行
复制
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上运行这个程序时--我看到了以下崩溃:

代码语言:javascript
运行
复制
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打印):

代码语言:javascript
运行
复制
#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;
}

在启动它之后,我看到了这个输出:

代码语言:javascript
运行
复制
➜  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解决了一个问题:

代码语言:javascript
运行
复制
addrInfos <- getAddrInfo (Just (defaultHints { addrFamily=AF_INET }))
               (Just host)
               (Just (show port))

但我仍然不知道如何“以正确的方式”解决这一问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-10-27 14:00:03

默认情况下,getaddrinfo (及其Haskell绑定getAddrInfo)返回一个可包含IPv4地址、IPv6地址或两者混合的addrinfo链接列表。不幸的是,套接字函数不允许将IPv4套接字连接到IPv6地址,因此在迭代地址列表时,需要创建正确类型的套接字:

代码语言:javascript
运行
复制
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返回的所有地址。当您这样做时,不要忘记关闭连接失败的套接字。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26588469

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档