问题描述
我正在使用.Net UdpCLient类在f#中创建UDP接收器,它看起来很简单:
let Start (ip: IPAddress,port : int32) : Async<unit> =
async {
try
let endpoint = IPEndPoint(ip,port)
use receivingClient = new UdpClient();
receivingClient.Client.Bind(endpoint)
let! receiveResult = receivingClient.ReceiveAsync() |> Async.AwaitTask
let receiveBytes = receiveResult.Buffer
printfn "%A" receiveBytes
with | ex -> raise (ex)
}
为了保持它的生命,我正在使用另一个使用rec函数的属性,它看起来像:
let Watcher (ip: IPAddress,port : int32) : unit =
let rec listenerWatcher () =
async {
try
do! Start (ip,port)
return! listenerWatcher()
with | :? UdpClientdisposedException ->
return ()
}
listenerWatcher() |> Async.Start
并且使用类型进行调用很简单:
UdpReceiver.Watcher (ip,port) (* where UdpReceiver is module name *)
我的问题是我只收到第一个传入的软件包,就像侦听器在收到第一个传入的软件包后关闭一样,这可能是什么问题?
解决方法
也许您的问题是发送包裹的速度太快。收到第一个程序包后,需要一些时间才能再次启动接收程序,但与此同时,发送方仍在发送下一个程序包。
不确定您的确切意图是什么,但是我认为您应该只启动(设置)接收程序一次,然后重复接收传入的程序包,并且仅在发生错误(引发异常)时重新启动接收程序。
顺便说一句,您的代码在F#中并不是真正惯用的,应该:
- 在元组中优先使用分隔的参数,这增加了使用curring的机会。
- 仅在需要时使用类型注释,这会使代码更短。
- 使用名称函数,使它们成为动词而不是名词,并使用camelCase样式。
我将如下重写您的代码:
let start (ip: IPAddress) port =
let endpoint = IPEndPoint (ip,port)
let receivingClient = new UdpClient ()
receivingClient.Client.Bind endpoint
let rec loop () = async {
printfn "Waiting..."
let! receiveResult = receivingClient.ReceiveAsync () |> Async.AwaitTask
let receiveBytes = receiveResult.Buffer
printfn "Receive: %A" receiveBytes
return! loop ()
}
loop ()
let watch ip port =
let rec loop () = async {
try
return! start ip port
with ex ->
printfn "Error: %s" ex.Message
return! loop ()
}
loop ()
// in main function or somewhere:
watch ... ... |> Async.Start...