如何在Haskell中的多播连接中指定源地址?

时间:2014-09-30 18:29:03

标签: haskell networking multicast

在网络多播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 = 32101

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

1 个答案:

答案 0 :(得分:1)

Haskell的作者在他们的构造函数中没有允许这样做。它根本不应该采用组参数,因为它不允许您在加入组之前设置组播接口。或者,该组应该是可选的。

另外我会说他们应该提供一个addMembership()覆盖或替代,它接受一个NIC地址和一个组地址。底层的Sockets系统调用毕竟支持它。

然而,除非Haskell的setInterface()方法根本不起作用,在这种情况下你无法做很多事情,顺序

dropMembership()
setInterface()
addMembership()

应该有用。

在我断定setInterface()无法正常工作之前,我想确认您确实没有看到任何IGMP消息传出该接口。

我怀疑真正发生的事情是发件人没有正确发送。