2016-08-04 2 views
0

지정된 포트에서 들어오는 연결을 수신 대기하기 위해 TcpListener을 시작하는 서버가 있습니다. 그것은 다음과 같이 구현됩니다System.AppDomainUnloadedException 스레드가 중지되지 않아서 테스트 중

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 : 무부하 응용 프로그램 도메인에 액세스하기 위해 시도했습니다. 테스트가 스레드를 시작했지만 스레드를 중지하지 않은 경우에 발생할 수 있습니다. 완료되기 전에 테스트 (들)에 의해 시작된 모든 스레드가 중지되었는지 확인하십시오.

내 코드를 살펴보면 재귀 루프가 실제로 끝나지 않았 음을 알았 기 때문에 그 원인이 될 수 있다고 생각했습니다. 내 솔루션은 서버를 멈출 때 Cancel()을 호출하는 취소 토큰을 추가하는 것이 었습니다. (이 코드는 붙여 넣었습니다. 처음에는 없었습니다).

불행히도이 문제는 해결되지 않았습니다. 이 예외 (내 테스트가 실패하지 않음)가 발생할 수있는 원인은 무엇입니까?

답변

0

밝혀졌습니다. 취소가 실제로 완료 될 때까지 기다릴 필요가있었습니다. 다음 작업을 수행하기 위해 생성 된 초기 작업에 대한 액세스 권한이 없기 때문에 cancellationToken.Cancel() 호출 후 2 초 동안 잠을 잤습니다.

관련 문제