2013-03-12 10 views
9

Używam usługi Google Cloud Messaging (GCM) dla mojej aplikacji na Androida. Zaimplementowałem go zgodnie ze wszystkimi zasadami i działa. Cóż prawie.Wysyłanie wiadomości GCM (po stronie serwera) często kończy się niepowodzeniem - ale daleko od zawsze

Najczęściej powiedziałbym, że w 60-70% przypadków mogę skutecznie wysłać wiadomość GCM z mojego serwera, korzystając z usługi internetowej opisanej na stronach internetowych Google.

Normalnie mam następującą odpowiedź od usługa, która wskazuje, że pomyślnie wysłana wiadomość GCM:

{ 
    "multicast_id":8378088572050307085, 
    "success":1, 
    "failure":0, 
    "canonical_ids":0, 
    "results": 
    [ 
     { 
      "message_id":"0:1363080282442710%7c4250c100000031" 
     } 
    ] 
} 

to mówiąc: wszystko OK, wiadomość została wysłana.

Jednak w wielu przypadkach pojawia się błąd HTTP podczas wywoływania usługa, która mówi:

Nie można odczytać danych z połączenie: Ustalona połączenie zostało przerwane przez oprogramowanie w komputerze hosta .

To jest wiadomość .NET, która mówi, że wywołanie usługi sieciowej (przy użyciu HttpWebRequest i POST) nie powiodło się.

to niektóre komunikaty dziennika, który pokazuje problem:

enter image description here

Jest to kod używam na wywołanie WS:

public static string SendMessage(string registrationId, string command, string extra, bool retry) 
{ 
    try 
    { 
     HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send"); 
     request.Method = PostWebRequest; 
     request.KeepAlive = false; 

     GCMPostPacket json = new GCMPostPacket() 
     { 
      collapse_key = "1", 
      time_to_live = 60, 
      registration_ids = new List<string>(new string[] { registrationId }), 
      data = new GcmData() 
      { 
       message = command, 
       misc = extra 
      } 
     }; 
     // Converting to JSON string 
     string jsonString = SICJsonProtocol.JSONHelper.Serialize<GCMPostPacket>(json); 
     byte[] byteArray = Encoding.UTF8.GetBytes(jsonString); 

     request.ContentType = "application/json"; 
     request.ContentLength = byteArray.Length; 
     request.ProtocolVersion = HttpVersion.Version10; 

     request.Headers.Add(HttpRequestHeader.Authorization, "key=" + "MyVerySecretKey"); 

     Stream dataStream = request.GetRequestStream(); 
     dataStream.Write(byteArray, 0, byteArray.Length); 
     dataStream.Close(); 

     using (WebResponse response = request.GetResponse()) 
     { 
      HttpStatusCode responseCode = ((HttpWebResponse)response).StatusCode; 
      if (responseCode.Equals(HttpStatusCode.Unauthorized) || responseCode.Equals(HttpStatusCode.Forbidden)) 
      { 
       Console.WriteLine("Unauthorized - need new token"); 
      } 
      else if (!responseCode.Equals(HttpStatusCode.OK)) 
      { 
       Console.WriteLine("Response from web service not OK :"); 
       Console.WriteLine(((HttpWebResponse)response).StatusDescription); 
      } 

      StreamReader reader = new StreamReader(response.GetResponseStream()); 
      string responseLine = reader.ReadLine(); 
      Console.WriteLine("************************"); 
      Console.WriteLine("GCM send: " + responseCode + " | " + responseLine); 
      // This is the log shown in the image above 
      SRef.main.gui.ServiceUpdate("GCM send: " + responseCode + " | " + responseLine); 
      reader.Close(); 
      response.Close(); 
      return responseLine; 
     } 

    } 
    catch (Exception e) 
    { 
     // This is the log shown in the image above 
     SRef.main.gui.ServiceUpdate("Failed send GCM, " + (retry ? "retrying in 20 sec" : "not retrying") + ". Error=" + e.Message); 
     if (retry) 
     { 
      System.Threading.ThreadPool.QueueUserWorkItem(delegate(object obj) 
      { 
       try 
       { 
        System.Threading.Thread.Sleep(20000); 
        SendMessage(registrationId, command, extra, false); 
       } 
       catch (Exception ex) 
       { 
       } 
      }); 
     } 
     return null; 
    } 
} 

Czy ktoś może sprawdzić, czy robię coś źle, lub jeśli brakuje mi czegoś ogólnie?

+2

Czy możliwe jest zarejestrowanie wartości 'e' wewnątrz zewnętrznego bloku catch? Może zawierać przydatne informacje. – Nachi

+0

Oczywiście, dodam to i zobaczę, czy to pomaga – Ted

+0

Właściwie już tam jest. e.Message jest zapisany na wyjściu, to jest komunikat o błędzie u widzisz tam ... * + ". Error =" + e.Message); * – Ted

Odpowiedz

3

Nie można odczytać danych z połączenia transportowego: ustanowione połączenie zostało przerwane przez oprogramowanie hosta.

Ten błąd nie ma nic wspólnego z GCM API w szczególności. Oznacza to, że klient próbował skontaktować się z usługą sieci Web, ale ustanowione połączenie zostało zerwane w jednej z warstw sieci. W zależności od tego, gdzie pojawi się ten błąd i komunikat o błędzie, może to oznaczać kilka rzeczy.

  1. Twój klient podjął decyzję o przerwaniu połączenia z powodu przekroczenia limitu czasu gniazda. Zwiększ czas oczekiwania na odczyt/gniazdo klienta, aby poprawić sytuację.

  2. System równoważenia obciążenia, który znajduje się między klientem a serwerem, odrzucił połączenie. Każda ze stron uważa, że ​​druga zrzuciła połączenie.

Limity czasu sieci są zwykle ogromnym problemem, ponieważ nigdy nie wiadomo, gdzie połączenie zostało zerwane i kto je upuścił. Jeśli wydłużanie czasu oczekiwania nie pomaga, sugerowałbym wysłanie żądań za pośrednictwem serwera proxy, który może wykryć ruch HTTPS (charles/TCPMON) lub użyć Wireshark, aby zobaczyć, które pakiety są usuwane.

Twoja aplikacja na Androida ma również funkcję monitorowania GCM, którą możesz włączyć na karcie Statystyki. Sprawdź, czy interfejs API GCM zgłasza na tym wykresie komunikat o stanie inny niż 200 OK. Pomoże to jeszcze bardziej ograniczyć problem.Jeśli nie ma raportów o kodach stanu innych niż 200, oznacza to, że GCM nigdy nie otrzymywał żądań interfejsu API.

+0

Wiem, że jest to problem z siecią, ale nie jest to ogólny problem z siecią, ponieważ jestem zawsze podłączony do Internetu (inaczej nie miałbym połączenia ze światem zewnętrznym itp.). Jest to coś konkretnego między moim serwerem a serwerami gcm. I to jest ten sam problem, jeśli uruchomię go na innym komputerze lub lokalnie. – Ted

+0

Zakładka Statystyki? Gdzie to jest? – Ted

+0

Po połączeniu swojego [identyfikatora nadawcy na konsoli] (http://support.google.com/googleplay/android-developer/answer/2663268?hl=pl) powinieneś zobaczyć status kodu odpowiedzi GCM. Przejdź do swojej aplikacji -> Statystyki -> Wybierz wiadomości GCM z menu rozwijanego -> Kliknij kartę "Kod odpowiedzi GCM". –

Powiązane problemy