Nie można odczytać danych z połączenia transportowego: istniejące połączenie zostało przymusowo zamknięte przez hosta zdalnego

104

Mam aplikację serwerową i czasami, gdy klient próbuje się połączyć, pojawia się następujący błąd:

wprowadź opis obrazu tutaj

UWAGA: komunikat „Nie można pobrać strumienia z klienta lub logowanie nie powiodło się” to tekst, który został dodany przeze mnie w instrukcji catch

a linia, na której się kończy (sThread: line 96) to:

tcpClient = (TcpClient)client;
clientStream = tcpClient.GetStream();
sr = new StreamReader(clientStream);
sw = new StreamWriter(clientStream);

// line 96:                 
a = sr.ReadLine();

Co może być przyczyną tego problemu? Pamiętaj, że nie zdarza się to cały czas

Alex
źródło

Odpowiedzi:

63

Ten błąd zwykle oznacza, że ​​maszyna docelowa jest uruchomiona, ale usługa, z którą próbujesz się połączyć, jest niedostępna. (Zatrzymał się, uległ awarii lub jest zajęty innym żądaniem).

W języku angielskim: Połączenie z maszyną (zdalnym hostem / serwerem / komputerem PC, na którym działa usługa) zostało nawiązane, ale ponieważ usługa nie była dostępna na tym komputerze, maszyna nie wiedziała, co zrobić z żądaniem.

Jeśli połączenie z maszyną nie było dostępne, zobaczysz inny błąd. Zapomniałem, co to jest, ale przypomina to „Usługa niedostępna” lub „Niedostępna”.

Edycja - dodano

Jest możliwe, że jest to spowodowane przez zaporę ogniową blokującą port, ale biorąc pod uwagę, że mówisz, że jest to sporadyczne („czasami, gdy klient próbuje się połączyć”), jest to bardzo mało prawdopodobne. Nie włączyłem tego pierwotnie, ponieważ wykluczyłem to mentalnie przed udzieleniem odpowiedzi.

David
źródło
1
chodzi o to, że kiedy uruchamiam serwer, około 50 klientów łączy się z moim serwerem. Zaimplementowałem rodzaj sygnału oczekiwania podczas akceptacji klienta ... coś w rodzaju while (Program.waitToFinishLoginAtClient == true && ajutor <30) {Thread.Sleep (300); ajutor ++; } client = this.tcpListener.AcceptTcpClient (); Program.waitToFinishLoginAtClient = true; ........... i Program.waitToFinishAtClient zostaje zmodyfikowany w wątku zawierającym klienta
Alex
czy to „czekanie” może być problemem?
Alex
1
czy powinienem po prostu na to pozwolić? nie, czekaj ?
Alex
1
Myślę, że Wait jest problemem. Nie znam wystarczająco Twojego kodu, aby mieć pewność, ale to z pewnością brzmi prawdopodobnie. Ciekawe, czy zbudowałeś własną usługę „na własnej skórze”, czy też używasz do tego WCF lub nawet Remotingu ...
David
Opierając się na tym małym fragmencie kodu, wydaje mi się, że można by uniknąć problemu „czekania”, gdyby znajdował się on w osobnym wątku dla każdego połączenia. Na wypadek, gdyby to przypuszczenie było słuszne, oto przykład wielowątkowej usługi TCP z wielowątkowością, która może ci pomóc: switchonthecode.com/tutorials/ ...
David
181

Otrzymałem ten błąd podczas dzwonienia do serwisu internetowego. Problem dotyczył również bezpieczeństwa na poziomie transportu. Mógłbym wywołać usługę sieciową za pośrednictwem projektu witryny internetowej, ale podczas ponownego użycia tego samego kodu w projekcie testowym otrzymywałbym wyjątek WebException zawierający tę wiadomość. Dodanie następującego wiersza przed nawiązaniem połączenia rozwiązało problem:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

Edytować

System.Net.ServicePointManager.SecurityProtocol - ta właściwość wybiera wersję protokołu Secure Sockets Layer (SSL) lub Transport Layer Security (TLS) do użycia dla nowych połączeń korzystających tylko ze schematu Secure Hypertext Transfer Protocol (HTTPS); istniejące połączenia nie są zmieniane.

Uważam, że SecurityProtocolkonfiguracja jest ważna podczas uzgadniania TLS podczas wybierania wersji protokołu.

Uzgadnianie TLS - ten protokół służy do wymiany wszystkich informacji wymaganych przez obie strony do wymiany rzeczywistych danych aplikacji przez protokół TLS.

ClientHello - klient wysyła komunikat ClientHello określający najwyższą wersję protokołu TLS, który obsługuje ...

ServerHello - serwer odpowiada komunikatem ServerHello zawierającym wybraną wersję protokołu ... Wybrana wersja protokołu powinna być najwyższą obsługiwaną przez klienta i serwer. Na przykład, jeśli klient obsługuje protokół TLS w wersji 1.1, a serwer obsługuje wersję 1.2, należy wybrać wersję 1.1; nie należy wybierać wersji 1.2.

Hans Vonn
źródło
8
to mnie uratowało! dzięki. w moim debugerze próbuję wywołać usługę https podczas testowania i mam problem z OP.
Blair Holmes
6
Czy wiemy więcej o tym, jak / dlaczego to działa? Zmagałem się z wywołaniem PostAsync i wydaje się, że to również naprawia mój błąd. Cieszę się, że zadziałało, ale chciałbym też wiedzieć, dlaczego.
Kevin Matlock
1
@HansVonn Dzięki za to! Zaoszczędziło mi mnóstwo czasu - w odniesieniu do tego, dlaczego to działa. Ogranicza tylko wersję TLS, której używasz podczas łączenia.
zdezorientowany i
1
Nie mogę uwierzyć, że to mnie znowu dopadło! Dzięki
Sergio A.
2
DZIĘKUJĘ CI! To doprowadzało mnie do szału.
mknopf
34

Mój konkretny scenariusz polegał na tym, że usługa aplikacji platformy Azure miała minimalną wersję TLS zmienioną na 1.2

Nie wiem, czy od teraz jest to ustawienie domyślne, ale zmiana z powrotem na 1.0 sprawiła, że ​​zadziałało.

Możesz uzyskać dostęp do ustawienia w „Ustawieniach SSL”.

Hugo Hilário
źródło
7
O mój Boże BARDZO DZIĘKUJĘ! Utknąłem na tym zbyt długo i sprawdziłem ustawienia SSL w aplikacji internetowej, a minimalna została ustawiona na 1,2 zamiast 1,0. Kiedy zmieniłem go z powrotem na 1.0 i zrestartowałem aplikację internetową, zadziałało! Dziękuję bardzo!
Mason
1
Wielkie dzięki, @ hugo-hilário, zadziwiająco też to zadziałało! Jak u licha udało ci się znaleźć tak trudne rozwiązanie! : D
hosjay
@hosjay to też było piekło dla mnie :)
Hugo Hilário
3
Uratowałem mojego dnia kolego!
Nitesh
Miałem ten problem z moją funkcją Azure Function v2
Pieter Heemeryck
17

Nie jestem pewien, która z poprawek w tych postach na blogu pomogła, ale jedna z nich rozwiązała ten problem dla mnie ...

http://briancaos.wordpress.com/2012/07/06/unable-to-read-data-from-the-transport-connection-the-connection-was-closed/

Sztuczka, która mi pomogła, polegała na tym, że przestałem używać WebRequest i zamiast tego użyć HttpWebRequest. HttpWebRequest pozwala mi grać z 3 ważnymi ustawieniami:

i

http://briancaos.wordpress.com/2012/06/15/an-existing-connection-was-forcibly-closed-by-the-remote-host/

  • KROK 1: Wyłącz KeepAlive
  • KROK 2: Ustaw ProtocolVersion na Version10
  • KROK 3: Ograniczenie liczby punktów serwisowych
SteveC
źródło
1
Ta odpowiedź rozwiązała ten sam problem dla mnie. Wyłączyłem „Keep Alive” w sekcji Http Response Headers w IIS7
drzounds
Powinienem dodać, że musiałem również dodać ten kod do pliku Reference.cs dla usługi sieciowej, która miała takie zachowanie. chronione przesłonięcie System.Net.WebRequest GetWebRequest (Uri uri) {System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest) base.GetWebRequest (uri); webRequest.KeepAlive = false; return webRequest; }
drzounds
11

Wywołania do usług HTTPS z jednego z naszych serwerów generowały również wyjątek „ Nie można odczytać danych z połączenia transportowego: istniejące połączenie zostało przymusowo zamknięte ”. Usługa HTTP działała jednak dobrze. Użył Wiresharka, aby zobaczyć, że był to błąd uzgadniania TLS. Skończyło się na tym, że zestaw szyfrów na serwerze wymagał aktualizacji.

Jobrocol
źródło
To właśnie się ze mną działo. A wysłano wygasły certyfikat do połączenia SSL. Odnów certyfikat i zadziałało.
Guilherme de Jesus Santos
8

Według odpowiedzi „Hansa Vonna”.

Dodanie następującego wiersza przed nawiązaniem połączenia rozwiązało problem:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

Po dodaniu protokołu Security i działaniu dobrze, ale muszę dodawać przed każdym wywołaniem API, które nie jest zdrowe. Po prostu aktualizuję platformę .net do wersji co najmniej 4.6 i działając zgodnie z oczekiwaniami nie wymagam dodawania przed każdym wywołaniem API.

Mahi Uddin
źródło
1
Dziękuję Ci bardzo. sprawiłeś, że mój dzień. Dla niektórych może się przydać, jeśli wspomnę, że wcześniej testowałem również dezaktywację zapory i dodanie ServicePointManager.ServerCertificateValidationCallback, ale nie działało.
Tekin
5

Nie pomoże to w przypadku sporadycznych problemów, ale może być przydatne dla innych osób z podobnym problemem.

Sklonowałem maszynę wirtualną i uruchomiłem ją w innej sieci z nowym adresem IP, ale nie zmieniłem powiązań w usługach IIS. Fiddler pokazywał mi komunikat „Nie można odczytać danych z połączenia transportowego: istniejące połączenie zostało przymusowo zamknięte przez hosta zdalnego”, a przeglądarka Internetowa poinformowała mnie „Włącz TLS 1.0, TLS 1.1 i TLS 1.2 w ustawieniach zaawansowanych”. Zmiana powiązania na nowy adres IP rozwiązała to za mnie.

Jon.Mozley
źródło
2

Z jakiegoś powodu połączenie z serwerem zostało utracone. Może się zdarzyć, że serwer jawnie zamknął połączenie lub błąd na serwerze spowodował nieoczekiwane zamknięcie połączenia. Lub coś między klientem a serwerem (przełącznik lub router) zrywało połączenie.

Może to być kod serwera, który spowodował problem, a może nie. Jeśli masz dostęp do kodu serwera, możesz umieścić tam trochę debugowania, aby poinformować Cię, kiedy połączenia klientów są zamykane. To może dać ci pewne wskazówki, kiedy i dlaczego połączenia są przerywane.

Na kliencie musisz napisać swój kod, aby uwzględnić możliwość awarii serwera w dowolnym momencie. Po prostu tak jest: połączenia sieciowe są z natury zawodne.

Jim Mischel
źródło
2

To rozwiązało mój problem. Dodałem tę linię przed wysłaniem żądania:

System.Net.ServicePointManager.Expect100Continue = false;

Wydawało się, że na drodze serwera znajduje się proxy, które nie obsługuje zachowania kontynuacji 100.

Mahdi Ataollahi
źródło
1

Mam ten problem w przeszłości. Używam PostgreSQL i kiedy uruchamiam mój program, czasami się łączy, a czasami wyświetla taki błąd.

Kiedy eksperymentuję z kodem, umieszczam kod połączenia w pierwszym wierszu poniżej formularza publicznego. Oto przykład:

PRZED:

    public Form1()
        {
        //HERE LIES SOME CODES FOR RESIZING MY CONTROLS DURING RUNTIME
        //CODE
        //CODE AGAIN
        //ANOTHER CODE
        //CODE NA NAMAN
        //CODE PA RIN!





        //Connect to Database to generate auto number
        NpgsqlConnection iConnect = new NpgsqlConnection("Server=localhost;Port=5432;User ID=postgres;Password=pass;Database=DB");
        iConnect.Open();
        NpgsqlCommand iQuery = new NpgsqlCommand("Select * from table1", iConnect);
        NpgsqlDataReader iRead = iQuery.ExecuteReader();
        NpgsqlDataAdapter iAdapter = new NpgsqlDataAdapter(iQuery);

        DataSet iDataSet = new DataSet();
        iAdapter.Fill(iDataSet, "ID");

        MessageBox.Show(iDataSet.Tables["ID"].Rows.Count.ToString());
        }

TERAZ:

    public Form1()
        {
        //Connect to Database to generate auto number
        NpgsqlConnection iConnect = new NpgsqlConnection("Server=localhost;Port=5432;User ID=postgres;Password=pass;Database=DB");
        iConnect.Open();
        NpgsqlCommand iQuery = new NpgsqlCommand("Select * from table1", iConnect);
        NpgsqlDataReader iRead = iQuery.ExecuteReader();
        NpgsqlDataAdapter iAdapter = new NpgsqlDataAdapter(iQuery);

        DataSet iDataSet = new DataSet();
        iAdapter.Fill(iDataSet, "ID");

        MessageBox.Show(iDataSet.Tables["ID"].Rows.Count.ToString());





        //HERE LIES SOME CODES FOR RESIZING MY CONTROLS DURING RUNTIME
        //CODE
        //CODE AGAIN
        //ANOTHER CODE
        //CODE NA NAMAN
        //CODE PA RIN!

        }

Myślę, że program musi najpierw przeczytać połączenie, zanim cokolwiek zrobi, nie wiem, popraw mnie, jeśli się mylę. Ale według moich badań nie jest to problem z kodem - w rzeczywistości pochodzi z samej maszyny.

Miłego kodowania!

Curbside Coder
źródło
1
System.Net.ServicePointManager.Expect100Continue = false;

Ten problem czasami występuje z powodu serwera proxy zaimplementowanego na serwerze WWW. Aby ominąć serwer proxy, umieszczając tę ​​linię przed wywołaniem usługi wysyłania.

Tahir Alvi
źródło
0

Miałem uruchomioną aplikację innej firmy (Fiddler), aby spróbować zobaczyć wysyłane żądania. Zamknięcie tej aplikacji rozwiązało problem

Johan Aspeling
źródło
0

Mieliśmy bardzo podobny problem, w którym witryna klienta próbowała połączyć się z naszą usługą interfejsu API sieci Web i otrzymać tę samą wiadomość. Zaczęło się to zupełnie nieoczekiwanie, kiedy nie było żadnych zmian kodu ani aktualizacji systemu Windows na serwerze, na którym były uruchomione usługi IIS.

W naszym przypadku okazało się, że strona wywołująca używa wersji .Net, która obsługuje tylko TLS 1.0 iz jakiegoś powodu serwer, na którym działały nasze IIS, przestał przyjmować połączenia TLS 1.0. Aby zdiagnozować, że musieliśmy jawnie włączyć TLS przez rejestr na serwerze IIS, a następnie ponownie uruchomić ten serwer. Oto klucze reg:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
    1.0\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
    1.0\Server] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
    1.1\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
    1.1\Server] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
    1.2\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
    1.2\Server] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

If that doesn't do it, you could also experiment with adding the entry for SSL 2.0:


    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client]
    "DisabledByDefault"=dword:00000000
    "Enabled"=dword:00000001

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server]
    "DisabledByDefault"=dword:00000000
    "Enabled"=dword:00000001

Moja odpowiedź na inne pytanie dotyczy tego skryptu PowerShell, którego użyliśmy do dodania wpisów:

UWAGA: Włączenie starych protokołów bezpieczeństwa nie jest dobrym pomysłem, właściwą odpowiedzią w naszym przypadku było skłonienie witryny klienta do zaktualizowania swojego kodu do korzystania z TLS 1.2, ale powyższe wpisy rejestru mogą pomóc zdiagnozować problem w pierwszej kolejności.

tomRedox
źródło
0

Powodem tego było to, że miałem rekursywną zależność u mojego dostawcy DI. W moim przypadku miałem:

services.AddScoped(provider => new CfDbContext(builder.Options));
services.AddScoped(provider => provider.GetService<CfDbContext>());

Naprawiono po prostu usunięcie drugiej rejestracji usługi w zakresie

services.AddScoped(provider => new CfDbContext(builder.Options));
Madison Haynie
źródło
0

Jeśli masz certyfikat https w domenie, upewnij się, że masz powiązanie https z nazwą domeny w usługach IIS. W usługach IIS -> Wybierz domenę -> Kliknij opcję Powiązania Otworzy się okno Powiązania witryny. Dodaj powiązanie dla https.

user2147447
źródło
0

Miałem podobny problem i otrzymywałem następujące błędy w zależności od używanej aplikacji i czy ominęliśmy zaporę / system równoważenia obciążenia, czy nie:

Uzgadnianie HTTPS do [bla] (dla # 136) nie powiodło się. System.IO.IOException Nie można odczytać danych z połączenia transportowego: istniejące połączenie zostało przymusowo zamknięte przez zdalnego hosta

i

ReadResponse () nie powiodło się: serwer nie zwrócił pełnej odpowiedzi na to żądanie. Serwer zwrócił 0 bajtów.

Problem polegał na tym, że certyfikat serwera SSL został pominięty i nie został zainstalowany na kilku serwerach.

śmiertelny pies
źródło
0

Spróbuj najpierw sprawdzić, czy możesz ustalić uścisk dłoni. Miałem ten problem wcześniej podczas przesyłania pliku i doszedłem do wniosku, że problem dotyczy nieistniejącej trasy, gdy usunąłem przesyłanie i sprawdziłem, czy można się zalogować, biorąc pod uwagę parametry.

Raffy
źródło
0

Dla mnie był to problem polegający na tym, że w powiązaniu IIS miał adres IP serwera internetowego. Zmieniłem to, aby używać wszystkich nieprzypisanych adresów IP i moja aplikacja zaczęła działać.

Shivaram Gopalakrishnan
źródło
0

Wystąpił błąd podczas wykonywania zapytania mdx do usług analitycznych firmy Microsoft przy użyciu narzędzia adomd w języku Python

Rozwiązałem to z pomocą Hansa Vonna i oto wersja w Pythonie :

clr.AddReference("System.Net")
from System.Net import ServicePointManager, SecurityProtocolType 
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls
Peter Kazmir
źródło
0

Dla tych, którzy mogą znaleźć to później, po wersji .NET 4.6, również napotkałem ten problem.

Upewnij się, że w pliku web.config znajdują się następujące wiersze:

<compilation debug="true" targetFramework="4.5">
...
<httpRuntime targetFramework="4.5" />

Jeśli korzystasz z 4.6.x lub nowszej wersji platformy .NET na serwerze, upewnij się, że dostosujesz te wartości targetFramework, aby pasowały do ​​wersji platformy na serwerze. Jeśli twoje wersje czytają mniej niż 4.6.x, to polecam aktualizację .NET i używanie nowszej wersji, chyba że twój kod jest zależny od starszej wersji (co w takim przypadku należy rozważyć aktualizację).

Zmieniłem targetFrameworks na 4.7.2 i problem zniknął:

<compilation debug="true" targetFramework="4.7.2">
...
<httpRuntime targetFramework="4.7.2" />

Nowsze frameworki rozwiązują ten problem, używając najlepszego dostępnego protokołu i blokując niezabezpieczone lub przestarzałe. Jeśli usługa zdalna, z którą próbujesz się połączyć lub wywołać, zgłasza ten błąd, może to oznaczać, że nie obsługują już starych protokołów.

Zachary Weber
źródło