簡體   English   中英

Haskell:不支持的操作(協議族不支持地址族)

[英]Haskell: Unsupported operation (Address family not supported by protocol family)

我有這段代碼連接到本地石墨(實際上只是在localhost上運行的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。 當我在升級到Yosemite后在我的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程序(用google搜索“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))

但我仍然想知道如何以“正確的方式”解決這個問題。

默認情況下, getaddrinfo (及其Haskell綁定getAddrInfo )返回addrinfo的鏈接列表,該列表可以包含IPv4地址,IPv6地址或兩者的混合。 不幸的是, 套接字函數不允許將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返回的所有地址。 當您這樣做時,不要忘記關閉連接失敗的套接字。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM