在网络多播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
答案 0 :(得分:1)
Haskell的作者在他们的构造函数中没有允许这样做。它根本不应该采用组参数,因为它不允许您在加入组之前设置组播接口。或者,该组应该是可选的。
另外我会说他们应该提供一个addMembership()
覆盖或替代,它接受一个NIC地址和一个组地址。底层的Sockets系统调用毕竟支持它。
然而,除非Haskell的setInterface()
方法根本不起作用,在这种情况下你无法做很多事情,顺序
dropMembership()
setInterface()
addMembership()
应该有用。
在我断定setInterface()
无法正常工作之前,我想确认您确实没有看到任何IGMP消息传出该接口。
我怀疑真正发生的事情是发件人没有正确发送。