我有一台服务器启动TcpListener
以侦听指定端口上的传入连接。它实现如下:
type TCPListenerServer(discoveryPort:int) =
let server = new TcpListener (IPAddress.Loopback, discoveryPort)
let activeConnections = new List<TcpClient>()
let cancellationToken = new System.Threading.CancellationTokenSource()
let rec loop (pendingConnection:Task<TcpClient>) = async {
let newPendingConnection, client =
match pendingConnection.Status with
| TaskStatus.Created | TaskStatus.WaitingForActivation | TaskStatus.WaitingToRun
| TaskStatus.WaitingForChildrenToComplete | TaskStatus.Running ->
(None, None)
| TaskStatus.Faulted ->
let result = pendingConnection.Exception
raise (new System.NotImplementedException())
| TaskStatus.Canceled ->
raise (new System.NotImplementedException())
| TaskStatus.RanToCompletion ->
let connectionTask = server.AcceptTcpClientAsync ()
(Some connectionTask, Some pendingConnection.Result)
| _ ->
raise (new System.NotImplementedException())
// Add the new client to the list
Option.iter (fun c -> activeConnections.Add c) client
// Switch the new pending connection if there is one
let connectionAttempt = defaultArg newPendingConnection pendingConnection
// Check that the connections are still alive
Seq.iter (fun (connection:TcpClient) -> if not connection.Connected then activeConnections.Remove connection |> ignore) activeConnections
Async.Sleep 1000 |> Async.RunSynchronously
return! loop connectionAttempt
}
member x.Start () =
try
server.Start ()
let connectionTask = server.AcceptTcpClientAsync ()
Async.Start (loop connectionTask, cancellationToken.Token)
with ex ->
server.Stop ()
member x.Stop () =
cancellationToken.Cancel ()
server.Stop ()
member x.ActiveConnections =
activeConnections
我正在做一个非常简单的测试,启动服务器并确保不会抛出异常,如下所示:
let cleanupTest (serverUsed:TCPListenerServer) =
serverUsed.Stop ()
[<TestMethod>]
[<TestCategory(Networking)>]
member x.``Start Server`` () =
let server = new TCPListenerServer(44000)
server.Start ()
Async.Sleep 5000 |> Async.RunSynchronously
cleanupTest server
测试通过,但我在测试结果中得到以下错误:
System.AppDomainUnloadedException:尝试访问已卸载的 AppDomain中。如果测试开始一个线程但没有开始,则会发生这种情况 停下来。确保测试启动的所有线程都是 在完成之前停止。
回顾我的代码时,我意识到我的递归循环从未实际完成,所以我认为这可能是原因。我的解决方案是在我停止服务器时添加取消令牌(这是我已粘贴的代码,最初没有在那里)我打电话给Cancel()
。
不幸的是,这还没有解决问题。什么可能导致这种异常(这不会导致我的测试失败)?
答案 0 :(得分:0)
原来我需要等到取消实际完成。我通过在调用cancellationToken.Cancel ()
后睡2秒来完成此操作,因为我无法访问为执行以下操作而创建的初始任务:
task.Wait ()