什么';这台f#echo服务器出了什么问题?
我写了这个f#echo服务器:什么';这台f#echo服务器出了什么问题?,f#,F#,我写了这个f#echo服务器: 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:
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())
开放系统.Net
开放式System.Net.Sockets
开放系统
开放系统
开放系统.Text
open System.Collections.Generic
让addr=IPAddress.Parse(“127.0.0.1”)
let listener=新的TcpListener(地址,2000)
listener.Start()
让rec loop2(c:TcpClient,sr:StreamReader,sw:StreamWriter)=异步{
let line=sr.ReadLine()
如果不是(line=null),则
匹配
|“退出”->
高级关闭()
sw.Close()
c、 关闭()
|_ ->
如果line.等于(“左”),那么
西南书写线(“右”)
返回!回路2(c、sr、sw)
西南写入线(行)
返回!回路2(c、sr、sw)
其他的
高级关闭()
sw.Close()
c、 关闭()
}
let loop()=异步{
尽管如此
设c=listener.AcceptCpcClient()
设d=c.GetStream()
设sr=新的StreamReader(d)
设sw=新StreamWriter(d)
sw.AutoFlush问题在于,与命令式语言中的同名函数不同,计算表达式中的return
不会短路。因此一旦if line.Equals(“右”)中的return!
返回,即在套接字关闭后,运行if
块后的代码并尝试写入关闭的套接字。解决方法是将这两行放入else
:
if line.Equals("left") then
sw.WriteLine("right")
return! loop2(c,sr,sw)
else
sw.WriteLine(line)
return! loop2(c,sr,sw)
作为一个附加的样式提示,整个主体可以实现为一个匹配
:
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 line.Equals("left") then
sw.WriteLine("right")
return! loop2(c,sr,sw)
sw.WriteLine(line)
return! loop2(c,sr,sw)
如果收到一个“left”,它将写入“right”,然后执行嵌套的loop2
s,直到收到一个“quit”。然后,在所有这些都完成之后,它将尝试写入line
,并执行更多嵌套的loop2
s。当然,此时,您已经处理了连接,因此出现了异常
似乎写入行
应该在else块中,这样可以防止错误:
if line.Equals("left") then
sw.WriteLine("right")
else
sw.WriteLine(line)
return! loop2(c,sr,sw)
当然,您也可以将此检查与模式匹配集成在一起。下面的示例将在一个结构中处理空检查和每个字符串选项
let line = Option.ofObj <| sr.ReadLine()
match line with
|None
|Some("quit") ->
sr.Close()
sw.Close()
|Some("left") ->
sw.WriteLine("right")
return! loop2(c,sr,sw)
|Some(line) ->
sw.WriteLine(line)
return! loop2(c,sr,sw)
然后,您可以创建一个正确的异步版本:
let rec handleClient (c:TcpClient) (sr:StreamReader) (sw:StreamWriter) =
async {
let! line = readLineAsync sr
match Option.ofObj(line) with
|None
|Some("quit")->
sr.Close()
sw.Close()
|Some("left") ->
do! writeLineAsync sw "right"
return! loop2(c,sr,sw)
|Some(line) ->
do! writeLineAsync sw line
return! loop2(c,sr,sw)
}
let loop() =
async {
let! c = acceptClientAsync listener
let sr = new StreamReader(c.GetStream())
let sw = new StreamWriter(c.GetStream())
sw.AutoFlush <- true
do! handleClient c sr sw |> Async.StartChild |> Async.Ignore
return! loop()
}
让rec处理客户端(c:TcpClient)(sr:StreamReader)(sw:StreamWriter)=
异步的{
让!line=readLineAsync sr
将选项ofObj(行)与匹配
|没有
|一些(“退出”)->
高级关闭()
sw.Close()
|一些(“左”)->
做!写下EasySync sw“正确”
返回!回路2(c、sr、sw)
|一些(行)->
执行!写入EASYNC sw行
返回!回路2(c、sr、sw)
}
让循环()
异步的{
let!c=acceptClientAsync侦听器
设sr=newstreamreader(c.GetStream())
设sw=newstreamwriter(c.GetStream())
sw.AutoFlush Async.StartChild |>Async.Ignore
return!loop()
}
您得到的异常是什么?您能将该信息添加到您的问题中吗?请将异常复制并粘贴到问题中,而不是使用屏幕截图。异常的屏幕截图不允许任何人通过谷歌搜索异常文本,因此帮助不大。另外,请让我们查看异常的整个堆栈跟踪,而不是just位于第一行。查看stacktrace的其余部分可能会提供一些线索,帮助用户找出导致异常的原因。
let rec handleClient (c:TcpClient) (sr:StreamReader) (sw:StreamWriter) =
async {
let! line = readLineAsync sr
match Option.ofObj(line) with
|None
|Some("quit")->
sr.Close()
sw.Close()
|Some("left") ->
do! writeLineAsync sw "right"
return! loop2(c,sr,sw)
|Some(line) ->
do! writeLineAsync sw line
return! loop2(c,sr,sw)
}
let loop() =
async {
let! c = acceptClientAsync listener
let sr = new StreamReader(c.GetStream())
let sw = new StreamWriter(c.GetStream())
sw.AutoFlush <- true
do! handleClient c sr sw |> Async.StartChild |> Async.Ignore
return! loop()
}