長い投稿で申し訳ありません。TcpListener
ポートでリッスンし、別の (バックグラウンド) スレッドで着信接続によって要求された重い作業を処理し、準備ができたらクライアントに応答を返すために使用したいと思います。私は MSDN で多くのコードとサンプルを読み、サーバーの次の実装を考え出しました。
以下のすべての実装について、次の変数を想定してください。
let sva = "127.0.0.1"
let dspt = 32000
let respondToQuery (ns_ : NetworkStream) (bta_ : byte array) : unit =
// DO HEAVY LIFTING
()
実装 1 (単純な同期サーバー。この MSDN ページのコードを翻訳したもの)
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 (この MSDN ページのコードの私の翻訳)
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 (非同期ワークフローの MSDN ページに基づく私の実装)
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"
Implementation 3
さて、MSDN のドキュメントを読んだところ、それが最速だったと思います。しかし、複数のマシンからの複数のクエリでサーバーにヒットすると、それらはすべてほぼ同じ速度で動作します。これにより、私は何か間違ったことをしているに違いないと信じるようになります。
バックグラウンドで重労働を行い、終了時にクライアントに応答を返し、別のクライアントが別のバックグラウンドスレッドで別のタスクに接続して開始できるようにする実装の「正しい」方法はどちらImplementation 2
ですか? そうでない場合は、どのクラス (またはチュートリアル) を読むべきか教えてください。Implementation 3
TcpListener