在尝试学习一些反应式编程的应用程序时,我一直在玩FSharp.Control.Reactive库。使用.NET TcpListener类侦听客户端是一个被动的过程,因此我决定使用Observables在F#中创建一个服务器(松散的术语)。我的测试用例是来自天文程序(Stellarium)的单个客户端连接,它在20字节的tcp套接字流中发送星形的天体坐标。我在下面的代码片段工作,但是使用Observables订阅TcpListener和连接的任何最终客户端流是一个好主意,或者实际上是否实用?什么是优势或劣势?
open System
open System.Net
open System.Net.Sockets
open System.Threading
open System.Reactive
open System.Reactive.Linq
open System.Reactive.Concurrency
open System.Reactive.Disposables
open FSharp.Control.Reactive.Builders
open FSharp.Control.Reactive.Observable
open FSharp.Control.Reactive.Disposables
type TcpListener with
member l.AcceptClientAsync = async {
let! client = Async.AwaitTask <| l.AcceptSocketAsync()
return client
}
let readCoordinates(coords : byte[]) =
let raInt = BitConverter.ToUInt32(coords, 12)
let decInt = BitConverter.ToInt32(coords, 16)
let ra_h = float raInt * 12.0 / 2147483648.0
let dec_h = float decInt * 90.0 / 1073741824.0
if (coords.Length > 0) then
Some (ra_h, dec_h)
else
None
let listen() =
let ipAddr = IPAddress.Any
let endpoint = IPEndPoint(ipAddr, 10001)
let listener = TcpListener(endpoint)
listener.Start()
observe.While ((fun () -> true), ofAsync(listener.AcceptClientAsync))
|> bind( (fun socket -> observe.Yield(new NetworkStream(socket))) )
|> bind(fun stream -> observe.While( (fun _ -> true), ofAsync(stream.AsyncRead(20)) ))
|> map (fun bytes -> readCoordinates bytes)
[<EntryPoint>]
let main argv =
listen()
|> subscribe (fun coords -> printfn "Target Coordinates %A" coords)
|> ignore
printfn "Hit enter to continue"
Console.Read() |> ignore
0