I've written this f# echo server:
open System.Net
open System.Net.Sockets
open System.IO
open System
open System.Text
open System.Collections.Generic
let addr = IPAddress.Parse("127.0.0.1")
let listener = new TcpListener(addr, 2000)
listener.Start()
let rec loop2(c:TcpClient,sr:StreamReader,sw:StreamWriter)=async {
let line=sr.ReadLine()
if not(line=null) then
match line with
|"quit"->
sr.Close()
sw.Close()
c.Close()
|_ ->
if line.Equals("left") then
sw.WriteLine("right")
return! loop2(c,sr,sw)
sw.WriteLine(line)
return! loop2(c,sr,sw)
else
sr.Close()
sw.Close()
c.Close()
}
let loop()=async {
while true do
let c=listener.AcceptTcpClient()
let d = c.GetStream()
let sr = new StreamReader(d)
let sw = new StreamWriter(d)
sw.AutoFlush<-true
Async.Start(loop2(c,sr,sw))
}
Async.RunSynchronously(loop())
This program can do:
but when I run the programming,when a client sent 'left',get 'right',and sent 'quit',i got this exception:
not handled exception: System.ObjectDisposedException: (con't write to closed) TextWriter。 in Microsoft.FSharp.Control.CancellationTokenOps.Start@1192-1.Invoke(Exception e) in .$Control.loop@419-40(Trampoline this, FSharpFunc
2 action) in Microsoft.FSharp.Control.Trampoline.ExecuteAction(FSharpFunc2 firstAction) in Microsoft.FSharp.Control.TrampolineHolder.Protect(FSharpFunc`2 firstAction) in [email protected](Object state) in System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state) in System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, BooleanpreserveSyncCtx) in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) in System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() in System.Threading.ThreadPoolWorkQueue.Dispatch() in System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() . . .(press any key to continue)
Screenshot of program in action
Screenshot of exception
how can i fix this problem?
The problem is that, unlike what you might expect from its namesake in imperative languages, return in a computation expression doesn't short-circuit. So once the return! in the if line.Equals("right") returns, ie. after the socket has been closed, the code after the if block is run and tries to write to the closed socket. The fix is to put those two lines in an else:
if line.Equals("left") then
sw.WriteLine("right")
return! loop2(c,sr,sw)
else
sw.WriteLine(line)
return! loop2(c,sr,sw)
As an additional style tip, this whole body can be implemented as a match:
let rec loop2(c:TcpClient,sr:StreamReader,sw:StreamWriter)=async {
let line=sr.ReadLine()
match line with
| null | "quit" ->
sr.Close()
sw.Close()
c.Close()
| "left" ->
sw.WriteLine("right")
return! loop2(c,sr,sw)
| _ ->
sw.WriteLine(line)
return! loop2(c,sr,sw)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With