2016-08-26 29 views
8

Próbowałem grać z .NET Core i chcę połączyć się z lokalnym serwerem TCP. Brak problemów, gdy robię to synchronicznie (patrz pierwsza metoda Connect). Kiedy próbuję to zrobić przy pomocy async/await (patrz druga metoda ConnectAsync), robi się szalona i prawie niewiarygodna. Nie jestem pozwany, jeśli używam TcpClient poprawnie, ponieważ nie ma tak wielu przykładów, które są jeszcze dostępne w Internecie. Dokładne problemy zaczynają się po wywołaniu TcpClient.GetStream. Próbowałem debugować to przy użyciu pola wyboru JustMyCode wyłączone i All exceptions w kodzie Visual Studio - ale po prostu nie przeskakuje ono do TcpClient.GetStream..NET Core: TcpClient.GetStream ulega awarii podczas korzystania z async

Obserwacje w trybie async:

  • czasami zawiesza go w TcpClient.GetStream bezpośrednio
  • czasami wywala to po powraca funkcji wywołującej (widziałem ostatni Console.WriteLine pojawia się w konsoli czasami)
  • program natychmiast zatrzymuje się, wyłącza debuger (bez wyjątku)
  • kod powrotu ma zawsze wartość zero (The program 'bla' has exited with code 0 (0x00000000))

Moja konfiguracja systemu/projekt:

  • 64bit systemu Windows 10 (Edukacja)
  • NET Rdzeń 1.0.0
  • aplikacja Console
  • lokalny serwer TCP, dlatego brak łączności wystawia
  • Kod Visual Studio Code (bez znaczenia)

Co de:

public class Connection 
{ 
    private TcpClient _client; 
    public NetworkStream Stream { get; private set; } 
    private CancellationTokenSource _token; 

    public Connection() 
    { 
     _token = new CancellationTokenSource(); 
     _client = new TcpClient(); 
    } 

    public void Connect(string host, int port) 
    { 
     Console.WriteLine("connecting..."); 
     _client.ConnectAsync(host, port); 
     Console.WriteLine("connected!"); 

     while (!_client.Connected) 
     { 
      Thread.Sleep(20); 
     } 

     Console.WriteLine("getting stream..."); 
     Stream = _client.GetStream(); // works because of Thread.Sleep above until the socket is connected 
     Console.WriteLine("got stream!"); 
    } 

    public async Task ConnectAsync(string host, int port) 
    { 
     Console.WriteLine("connecting..."); 
     await _client.ConnectAsync(host, port); 
     Console.WriteLine("connected!"); 

     // I know I could check for TcpClient.Connected but I see in debugger that the property is True 

     Console.WriteLine("getting stream..."); 
     Stream = _client.GetStream(); // crash in GetStream/crash after this function has returned 
     Console.WriteLine("got stream!"); // sometimes this is going to be printed, sometimes not 
    } 

    // ... 
} 
+0

Jestem zaintrygowany wersją connect (nie asynchroniczną) .. połącz, podczas gdy połączony śpisz, teraz spróbuj dostać strumień .. Nie rób tego w drugim ..po prostu łączysz się i spodziewasz się uzyskać strumień .. – BugFinder

+0

Czy dzwonisz do ConnectAsync tylko jeden raz lub wiele razy w tej samej instancji? – Guillaume

+2

Czy próbowałeś uzyskać wyjątek, który został rzucony? Może to daje wskazówkę. Byłoby dobrze, gdybyś mógł podzielić się tym. – Nitram

Odpowiedz

4

Problem, który opisujesz, wskazuje na główny wątek twojej aplikacji. Aby poprawnie zidentyfikować ten problem, należy spojrzeć na wszystkie aplikacje i wątki, które są aktywne w danym momencie.

Ale na przykład prosta aplikacja konsolowa kończy działanie, jak tylko główny sub zostanie przerwany. W zależności od tego, jak nazywasz swoją funkcję ConnectAsync, może ci brakować czegoś, co zapewni, że pętla główna nie zostanie zakończona. Upewnij się, że głównym punktem początkowym nie jest funkcja async, ponieważ zostanie ona zakończona, gdy tylko osiągnie pierwszy numer await.

Główna różnica między tymi dwoma metodami polega na tym, że metoda ConnectAsync faktycznie przełącza wątki bardzo prawdopodobne i wykonuje drugą część w innym wątku, nie blokując wątku, do którego została wywołana, tak jak robi to funkcja Connect.

Wyjaśnia dokładnie zachowanie, które opisujesz. Po pewnym czasie wykonywania linii zostanie zakończona główna pętla aplikacji i spowoduje ona zakończenie działania maszyny wirtualnej .NET.

+0

Dziękuję za tonę! Szacunek dla uzyskania tego, nawet nie wiedząc, jak nazywam 'ConnectAsync'. Rozwiązaniem było po prostu pozwolić, aby punkt wejścia czekał na wynik wywołania funkcji, który wywołuje 'ConnectAsync'. –