【发布时间】:2013-02-22 17:12:43
【问题描述】:
抱歉,帖子太长了。我想使用TcpListener 监听端口,处理不同(后台)线程中传入连接请求的繁重工作,然后在准备好时将响应发送回客户端。我在 MSDN 上阅读了很多代码和示例,并为服务器提出了以下实现。
对于以下所有实现,请假设以下变量:
let sva = "127.0.0.1"
let dspt = 32000
let respondToQuery (ns_ : NetworkStream) (bta_ : byte array) : unit =
// DO HEAVY LIFTING
()
实现 1(普通的同步服务器;我翻译的 the code from this MSDN page)
let runSync () : unit =
printfn "Entering runSync ()"
let (laddr : IPAddress) = IPAddress.Parse sva
let (svr : TcpListener) = new TcpListener (laddr, dspt)
try
svr.Start ()
let (bta : byte array) = Array.zeroCreate<byte> imbs
while true do
printfn "Listening on port %d at %s" dspt sva
let (cl : TcpClient) = svr.AcceptTcpClient ()
let (ns : NetworkStream) = cl.GetStream ()
respondToQuery ns bta
cl.Close ()
svr.Stop ()
printfn "Exiting runSync () normally"
with
| excp ->
printfn "Error: %s" excp.Message
printfn "Exiting runSync () with error"
实现2(我对代码on this MSDN page的翻译)
let runAsyncBE () : unit =
printfn "Entering runAsyncBE ()"
let (tcc : ManualResetEvent) = new ManualResetEvent (false)
let (bta : byte array) = Array.zeroCreate<byte> imbs
let datcc (ar2_ : IAsyncResult) : unit =
let tcpl2 = ar2_.AsyncState :?> TcpListener
let tcpc2 = tcpl2.EndAcceptTcpClient ar2_
let (ns2 : NetworkStream) = tcpc2.GetStream ()
respondToQuery ns2 bta
tcpc2.Close ()
tcc.Set () |> ignore
let rec dbatc (tcpl2_ : TcpListener) : unit =
tcc.Reset () |> ignore
printfn "Listening on port %d at %s" dspt sva
tcpl2_.BeginAcceptTcpClient (new AsyncCallback (datcc), tcpl2_) |> ignore
tcc.WaitOne () |> ignore
dbatc tcpl2_
let (laddr : IPAddress) = IPAddress.Parse sva
let (tcpl : TcpListener) = new TcpListener (laddr, dspt)
try
tcpl.Start ()
dbatc tcpl
printfn "Exiting try block"
printfn "Exiting runAsyncBE () normally"
with
| excp ->
printfn "Error: %s" excp.Message
printfn "Exiting runAsyncBE () with error"
实现3(我的实现基于the MSDN page for asynchronous workflows)
let runAsyncA () : unit =
printfn "Entering runAsyncA ()"
let (laddr : IPAddress) = IPAddress.Parse sva
let (svr : TcpListener) = new TcpListener (laddr, dspt)
try
svr.Start ()
let (bta : byte array) = Array.zeroCreate<byte> imbs
while true do
printfn "Listening on port %d at %s" dspt sva
let (cl : TcpClient) = svr.AcceptTcpClient ()
let (ns : NetworkStream) = cl.GetStream ()
async {respondToQuery ns bta} |> Async.RunSynchronously
cl.Close ()
svr.Stop ()
printfn "Exiting runAsyncA () normally"
with
| excp ->
printfn "Error: %s" excp.Message
printfn "Exiting runAsyncA () with error"
现在,根据我对 MSDN 文档的阅读,我认为Implementation 3 会是最快的。但是当我用来自多台机器的多个查询访问服务器时,它们都以大致相同的速度运行。这让我相信我一定做错了什么。
Implementation 2 或 Implementation 3 是实现 TcpListener 的“正确”方式,它在后台执行繁重的工作,并在完成后将响应返回给客户端,同时允许另一个客户端可能还连接并在另一个后台线程中启动另一个任务?如果没有,请告诉我应该阅读哪些课程(或教程)?
【问题讨论】:
标签: asynchronous f# async-await tcplistener