由连接到 IPAddress.Any 和 127.0.0.1 的两个客户端处理 UDP 数据包
Process UDP packet by two clients connected to IPAddress.Any and 127.0.0.1
我正在尝试将两个 UdpClient 连接到一个端口,以便它们并行读取数据并在两个单独的队列中处理请求。但由于某种原因,只有一个客户端收到数据包。
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
删除其中一个客户端可以使另一个客户端很好地读取数据包。
有没有办法让他们都收到数据包?
不,一般来说,一旦数据包 'removed from the TCP/UDP stack' 就被视为已处理。第一个客户端在收到它时将其删除,从 OS 和框架的角度来看,它已被处理,不会被传递给更多的听众。
您必须分两步实施您的解决方案:1 个 UDP 侦听器接收数据并将其交给 2 个处理器并行处理。
But for some reason only one of the clients receives the packets.
嗯,原因是,每个 IP 堆栈都是这样设计的。
除了@Mau的建议,如果你的平台是Linux,iptables
或许可以达到你想要的效果:
虽然两个答案都是正确的,但实际上可以使用 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
我正在尝试将两个 UdpClient 连接到一个端口,以便它们并行读取数据并在两个单独的队列中处理请求。但由于某种原因,只有一个客户端收到数据包。
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
删除其中一个客户端可以使另一个客户端很好地读取数据包。
有没有办法让他们都收到数据包?
不,一般来说,一旦数据包 'removed from the TCP/UDP stack' 就被视为已处理。第一个客户端在收到它时将其删除,从 OS 和框架的角度来看,它已被处理,不会被传递给更多的听众。
您必须分两步实施您的解决方案:1 个 UDP 侦听器接收数据并将其交给 2 个处理器并行处理。
But for some reason only one of the clients receives the packets.
嗯,原因是,每个 IP 堆栈都是这样设计的。
除了@Mau的建议,如果你的平台是Linux,iptables
或许可以达到你想要的效果:
虽然两个答案都是正确的,但实际上可以使用 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