2014-09-30 1 views
4

В документации Haskell сети многоадресной я вижу функциюКак указать адрес источника в многоадресном соединении в Haskell?

setInterface :: Socket -> HostName -> IO() 
Set the outgoing interface address of the multicast. 

Как я могу использовать это, чтобы указать исходный адрес в многоадресного присоединиться? Следующий код, когда бежал, производит данный вывод .. (IP-адрес замаскирован на частную жизнь)

кода

import Network.BSD 
import Network.Socket hiding (send, sendTo, recv, recvFrom) 
import Network.Socket.ByteString 
import Network.Multicast hiding (multicastReceiver) 
import Text.Printf 
import Data.ByteString as B hiding (putStrLn) 

sourceIP = "192.168.MMM.NNN" 
mcastIP = "224.0.XXX.YYY" 
mcastPort =1 

mcastLoop :: Socket -> IO() 
mcastLoop sock = do 
    (msg, addr) <- recvFrom sock 1024 
    printf "%s-> %s\n" (show addr) (show . B.unpack $ msg) 
    mcastLoop sock 

multicastReceiver :: HostName -> PortNumber -> IO Socket 
multicastReceiver host port = do 
    proto <- getProtocolNumber "udp" 
    sock <- socket AF_INET Datagram proto 
    setInterface sock sourceIP 

{-# LINE 81 "src/Network/Multicast.hsc" #-} 
    setInterface sock sourceIP 
    bindSocket sock $ SockAddrInet port 0 
    setInterface sock sourceIP 
{-# LINE 82 "src/Network/Multicast.hsc" #-} 
    setInterface sock sourceIP 
    addMembership sock host 
    return sock 

main :: IO() 
main = withSocketsDo $ do 
    sock <- multicastReceiver mcastIP mcastPort 
    dropMembership sock mcastIP 
    setInterface sock sourceIP 
    addMembership sock mcastIP 
    mcastLoop sock 

Выход

~ - sudo tcpdump -n -nn -i any "host 224.0.XXX.YYY" 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode 
listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes 
08:00:44.463153 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY 
08:00:52.498722 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY 
08:00:58.301711 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY 
08:01:08.408710 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY 
08:02:04.104707 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY 
08:03:08.545718 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY 
08:04:02.634709 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY 
08:05:03.757718 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY 
08:06:10.600716 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY 
08:07:07.248707 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY 
08:08:10.202708 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY 
08:09:02.390708 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY 

Это сравнение C++/Haskell приложений, выполняющихся (по запросу EJP)

~/sandbox - sudo tcpdump -i any "host 192.168.MMM.NNN"   
[sudo] password for gresko: 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode 
listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes 

# C++ application started 
16:15:55.490156 IP 192.168.MMM.NNN > 224.0.62.108: igmp v2 report 224.0.62.108 
# C++ application killed 
16:16:04.689342 IP 192.168.MMM.NNN > all-routers.mcast.net: igmp leave 224.0.62.108 

# Haskell application started 
# Haskell application killed 
+0

Этот вопрос аналогичен, но не отвечает на мой вопрос: http://stackoverflow.com/questions/6111204/how-to-specify-a-local-bond-interface-to-multicast-socket-in-haskell – gsk

+0

Можете ли вы уточнить, что «не работает»? Какое поведение вы ожидаете от того, что видите? – bheklilr

+0

Выполнено ожидаемое поведение – gsk

ответ

1

Авторы Haskell не допускают этого в t конструктор-наследник. Он не должен принимать параметр группы вообще, поскольку он не позволяет вам установить интерфейс многоадресной передачи, прежде чем присоединяться к группе. Или группа должна быть факультативной.

Также я бы сказал, что они должны предоставить переопределение или альтернативу addMembership(), которая берет NIC-адрес, а также адрес группы. В любом случае, базовый системный вызов Sockets поддерживает его.

Однако если метод Хаскелла setInterface() не работает вообще, в этом случае существует не так много вы можете сделать, последовательность

dropMembership() 
setInterface() 
addMembership() 

должен работать.

Я хотел бы подтвердить, что вы действительно не видите никаких сообщений IGMP, выходящих из этого интерфейса, прежде чем я пришел к выводу, что setInterface() не работает.

Я подозреваю, что на самом деле происходит то, что отправитель не отправляет должным образом.

+0

Хорошая идея. Я объединил кульминацию советов в один образец кода/вывода в исходном сообщении. Взгляните и дайте мне знать, что вы думаете. EDIT: Заметьте, это интересно, потому что установка неверного IP-адреса источника (ака IP, не обладающего каким-либо интерфейсом на компьютере) в 'setInterface' дает ошибку. Так кажется, что он действительно делает что-то *. – gsk

+0

'-i any' означает« обнюхивать »на всех интерфейсах,« host x.y.z.w »означает захват трафика на/из указанного узла. Эквивалентный захват из C++ показывает, что исходящие пакеты имеют «192.168.MMM.NNN» в качестве исходного IP-адреса. Кроме того, если «отчет о членстве» не является объединением, что такое? – gsk