由连接到IPAddress.Any和127.0.0.1的两个客户端处理UDP数据包

时间:2015-01-26 15:20:43

标签: .net sockets f# udp udpclient

我正在尝试将两个UdpClients连接到一个端口,以便它们并行读取数据并在两个单独的队列中处理请求。但由于某种原因,只有一个客户端接收到数据包。

let listen (local:IPEndPoint) =
    async {
        use client = new UdpClient()
        client.ExclusiveAddressUse <- false
        client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true)
        client.Client.Bind(local);

        printfn "Listen: %A" local.Address

        while true do
            let mutable remote = local
            client.Receive(&remote) |> ignore
            printfn "%A: %A" local.Address remote.Address
    }

Async.Parallel [
    listen(new IPEndPoint(IPAddress.Any, 5353));
    listen(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5353));
    async {
        while true do
            do! Async.Sleep 500

            use senderUC = new UdpClient()
            senderUC.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true)
            senderUC.Send([|byte(1)|], 1, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5353)) |> ignore

            printfn "sent to 127.0.0.1"
    }
] |> Async.RunSynchronously |> ignore


Thread.Sleep 10000

输出如下:

Listen: 127.0.0.1
Listen: 0.0.0.0
sent to 127.0.0.1
127.0.0.1: 127.0.0.1
...
sent to 127.0.0.1
127.0.0.1: 127.0.0.1

删除其中一个客户端会使另一个客户端很好地读取数据包。

这是一种让他们两个都接收数据包的方法吗?

3 个答案:

答案 0 :(得分:2)

不,通常一旦将数据包从TCP / UDP堆栈中删除,就会被视为已处理。第一个客户端在收到它时将其删除,从操作系统和框架的角度来看,它已被处理,不会传递给更多的监听器。

您必须分两步实施您的解决方案:1接收数据的UDP侦听器并将其交给2个并行处理它的处理器。

答案 1 :(得分:1)

  

但由于某种原因,只有一个客户端接收到数据包。

嗯,原因是,每个IP堆栈的设计方式都是如此。

除了@Mau的建议,如果您的平台是Linux,iptables也许可以实现您的目标:

答案 2 :(得分:0)

虽然两个答案都是正确的,但实际上可以使用UDP多播。但是,这要求网络中的路由器实际上支持多播。要使用多播,您可以在套接字上设置更多选项

//Creates a multicast publisher
let publisher multicastGroup ttl =
    let client = new UdpClient()
    client.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastGroup, IPAddress.Any))
    client.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, ttl)
    client

//Creates a multicast listener
let listener port multicastGroup =
    let client = new UdpClient()
    client.ExclusiveAddressUse <- false
    client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true) 
    client.Client.Bind(new IPEndPoint(IPAddress.Any, port))
    client.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastGroup, IPAddress.Any))
    client

然后您可以像在代码中一样使用发送和接收方法。有关此示例,请参阅here