2013-03-20 14 views
8

Natrafiamy na interesujący problem. Oto co nasz setup wygląda następująco:Rozłączenie klienta SignalR .NET

  • SignalR Server (aplikacji ASP.NET MVC) w systemie Windows Server 2012.
  • Sencha HTML5 apps (klienci SignalR) na tym samym serwerze (Windows Server 2012).
  • . Usługa Windows .NET na serwerze z systemem Windows Server 2008 R2. Działa to również jako klient SignalR.

Początkowo używaliśmy SignalR 0.5.3 - kiedy zaczęliśmy obserwować, że połączenie z usługą Windows do serwera R sygnału zanika. Częstotliwość tego wynosi od kilku minut do kilku godzin. Ponownie łączy się w większości przypadków, ale nie nawiązuje połączenia ponownie, co powoduje, że usługa Windows traci połączenie raz na kilka dni. Ale nie ma na to ustalonego wzorca. Nie jest to związane z restartowaniem/tworzeniem kopii zapasowych serwerów itp. Dodaliśmy rejestrowanie do usługi systemu Windows w celu monitorowania zdarzenia StateChanged na połączeniu z klientem i stwierdziliśmy, że zdarzenie zostanie wywołane, gdy nastąpi rozłączenie i ponowne połączenie, ale nie wtedy, gdy nie zostanie ponownie nawiązane połączenie.

Następnie natrafiliśmy tym wątku: client constantly reconnecting

i postanowił uaktualnić wszystko SignalR 1.0.1 (mieliśmy to robić w pewnym momencie). Usługa Windows została również zaktualizowana do frameworka 4.5 (z wersji 2.0), odwołując się teraz do nowego pliku Microsoft.AspNet.SignalR.Client.dll. Pozwoliło to również nam (przy użyciu nowo dodanej właściwości połączenia) ustalić, że usługa Windows faktycznie używała protokołu ServerSentEvents. Instalowanie tej samej usługi systemu Windows na komputerze z systemem Windows Server 2012 korzysta z protokołu WebSockets. Jest to zgodne z tym wątkiem: SignalR .NET Client doesn't support WebSockets on Windows 7

Jednak zachowanie usługi na serwerze Windows Server 2008 R2 nie uległo zmianie. Nadal rozłącza się i ponownie łączy, a od czasu do czasu traci połączenie. Z powodu kilku ograniczeń nie możemy używać serwera Windows 2012 do obsługi systemu Windows i utknąć w starszych systemach operacyjnych. Nie oznacza to, że usługa Windows wykorzystująca protokół websockets rozwiąże wszystkie nasze problemy (nie testowaliśmy tego dokładnie).

Trzecią rzeczą, którą próbowaliśmy, było pobranie kodu źródłowego z GitHub i skompilowanie go oraz uaktualnienie usług (SignalR Server i klientów) - zrobiono to, aby uzyskać najnowszą kopię z ewentualnymi poprawkami.

Ale to nie pomogło. Jesteśmy teraz w punkcie, w którym czujemy, że wyczerpaliśmy nasze możliwości. Sugestie będą bardzo mile widziane. Dzięki.

=====================================

EDIT: więcej informacji :

OK, teraz mamy więcej informacji. Dodaliśmy kod do usługi Windows (SignalR Client), aby logować się do serwera SignalR co 30 minut (do testowania połączenia).

Oto, co dzieje się po stronie klienta co 30 minut:

WriteEvent(Now(), "INFO", "PING", "Performing logon procedure with SiteCode = " & msSiteCode & ".") 
trans.Invoke("login", New String() {msSiteCode, "", "SERVER", "", ""}) 

gdzie trans jest instancją klasy po stronie serwera dziedziczy z Hub i WriteEvent jest w zasadzie śladu zapisu do pliku dziennika .

i po stronie klienta ma również „isLoggedIn metody” w następujący sposób:

Private Sub isLoggedIn(ByVal bLoggedIn As String) 
     If bLoggedIn Then 
      WriteEvent(Now(), "INFO", "", "SignalR Server: Authenticated")   
     Else 
      WriteEvent(Now(), "ERROR", "", "SignalR Server: Authentication failed") 
     End If 
End Sub 

Po stronie serwera mamy metodę logowania:

Public Sub login(ByVal sAccount As String, _ 
        ByVal sCompanyCode As String, _ 
        ByVal sClientId As String, _ 
        ByVal sPassword As String, _ 
        ByVal sModuleCode As String) 
     Try 
      'Some code omitted that validates the user and sets bValidated. 

      If bValidated Then 
       'Update user in cache 
       ConnectionCache.Instance.UpdateCache(userId, Context.ConnectionId, UserCredential.Connection_Status.Connected) 
       Clients.Caller.isLoggedIn(True) 

       Dim connectionId As String = ConnectionCache.Instance.FindConnectionId(userId) 
       LogEvent("Successful login for connectionid: " & connectionId & ". Context. User: " & userId, _ 
         EventLogEntryType.Information) 
      Else 
       Clients.Caller.isLoggedIn(False, results) 
      End If 
     Catch ex As Exception 
      LogEvent("Login: " & ex.Message, EventLogEntryType.Error) 
     End Try 
End Sub 

Jeśli spojrzymy na pliku dziennika klienta , co 30 minut otrzymujemy następujące wpisy dziennika:

  • Wykonywanie procedury logowania z SiteCode = ABCD.
  • SignalR Serwer: przysięgłe

Więc wiemy, że metoda logowania po stronie serwera jest nazywany, a metoda po stronie klienta isLoggedIn jest również tzw.

Jednak w pewnym momencie, gdy wywoływana jest metoda po stronie serwera, nie jest wywoływana metoda po stronie klienta isLoggedIn. Tak więc co 30 minut, zaczynamy uzyskiwać tylko jeden wpis:

  • Wykonywanie procedury logowania z SiteCode = ABCD.

Ponadto zdarzenie dziennika:

LogEvent("Successful login for connectionid: " & connectionId & ". Context. User: " & userId, EventLogEntryType.Information) 

w sposobie logowania po stronie serwera zostanie opisana w dzienniku po stronie serwera. Tak więc Clients.Caller.isLoggedIn (True) zostaje wywołany zgodnie z oczekiwaniami, ale nie widzimy tego po stronie klienta.

Domyślam się, że klient zawsze ma dostęp do serwera i jest w stanie wywołać funkcję po stronie serwera (logowanie), ale serwer nie może wywołać funkcji po stronie klienta (isLoggedIn), oraz to się w pewnym momencie zaczyna dziać.

Co więcej, może to być specyficzne dla klientów .NET, ponieważ jestem pewien, że nie widzieliśmy tego z naszymi klientami HTML5/javascript.

+0

Jeśli chcesz, możesz wypróbować pakiet nocny dla klienta w tym myget feed www.myget.org/F/aspnetwebstacknightly/. Mamy teraz rejestrowanie po stronie klienta (połączenie ma właściwość TextWriter connection.Trace). Możesz użyć tego, by zobaczyć, co się dzieje i dlaczego rzeczy nie zachowują się w Twojej sieci. – davidfowl

+0

Dzięki. Zarejestrowaliśmy już kilka wydarzeń i zaktualizowaliśmy oryginalne pytanie, podając więcej informacji. – smitra

+0

Potrzebujesz rejestrowania po stronie klienta, a nie po stronie serwera. – davidfowl

Odpowiedz

2

W końcu stworzyliśmy prostą funkcję "PINGING". To się nazywa co 15 minut. Logika wygląda następująco:

  1. Klient SignalR ma timer, który wywołuje metodę PING serwera co 15 minut.
  2. Podczas wywołania serwer wywołuje PINGCLIENT klienta na kliencie.
  3. W następnym zdarzeniu timera PING na kliencie (po 15 minutach) sprawdzamy, czy otrzymaliśmy odpowiedź. Jeśli nie, zawiesimy całą aktywność i ponownie zainicjalizujemy połączenie Hub. Następnie uruchom ponownie zegar PINGING.

Podczas gdy daliśmy sobie spokój, próbując dowiedzieć się, co było przyczyną, mamy obejście pozwalające zarządzać utratą połączenia "serwer-klient", kiedy to się stanie. Zauważ, że jest to dodatek do wbudowanej logiki ponownego połączenia w signalR.

Prowadzimy również dzienniki i średnio tak się dzieje (klient nie otrzymuje PING-a z serwera) może raz dziennie.

Powiązane problemy