У меня есть этот фрагмент кода, подключающийся к локальному графиту (который на самом деле просто 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 после обновления до Yosemite, я вижу следующий сбой:
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. ' sources и был удивлен, увидев, что он не обрабатывает там значение 30 (не знает о AF_TIPC).
У меня есть вопросы: что лучше всего сделать сейчас? Я правильно понял задачу? Должен ли Haskell лучше обрабатывать неизвестное семейство ИИ? // спасибо!
ОБНОВЛЕНИЕ: я решил проблему, добавив подсказку для использования ipv4:
addrInfos <- getAddrInfo (Just (defaultHints { addrFamily=AF_INET }))
(Just host)
(Just (show port))
но мне все еще интересно, как решить этот вопрос "правильным путем".
AF_*
вместо чисел, заключается в том, что числа не одинаковы в каждой системе. Linuxsocket.h
не говорит вам, что означает 30 в операционных системах, отличных от Linux. Лучше проверьтеsocket.h
на своей машине. (Я предсказываю, что 30 будетAF_INET6
) - person   schedule 27.10.2014AddrInfo {addrFlags = [], addrFamily = AF_INET6, addrSocketType = Datagram, addrProtocol = 17, addrAddress = [::1]:2023, addrCanonName = Nothing}
я вижу, что он правильно разрешил addrFamily в AF_INET6, но мне интересно, что означает addrProtocol 17. Единственная вещь со значением 17, которую я нашел, это#define AF_ROUTE 17 /* Internal Routing Protocol */
- person Konstantine Rybnikov   schedule 27.10.2014IPPROTO_UDP
. Если вы хотите использовать это поле результатаgetaddrinfo
, оно передается третьим аргументом вsocket()
. Обычно вы можете поставить 0, потому что семейства адресов и типа сокета (SOCK_DGRAM
,SOCK_STREAM
и т. д.) достаточно для однозначного определения протокола. - person   schedule 27.10.2014