2013-03-12 1 views
9

Я использую сервис Google Cloud Messaging (GCM) для своего приложения для Android. Я реализовал его в соответствии со всеми правилами, и он работает. Ну, почти.Отправка сообщения GCM (серверная сторона) часто терпит неудачу - но далеко не всегда

Чаще всего, я бы сказал, что в 60-70% случаев я могу успешно отправить сообщение GCM с моего сервера, используя веб-сервис, как описано на веб-страницах google.

Обычно я получаю следующий ответ от веб-сервиса, который указывает, что я успешно отправил сообщение GCM:

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

Это говорит: все ОК, сообщение отправлено.

Однако во многих случаях я получаю сообщение об ошибке HTTP при вызове веб-сервиса, который говорит:

Невозможно прочитать данные из транспортного соединения: установлено соединение было прервано с помощью программного обеспечения в вашей машине ,

Это сообщение .NET, чтобы сообщить мне, что вызов веб-службы (с использованием HttpWebRequest и POST) завершился неудачно.

Это некоторые сообщения журнала, который показывает проблему:

enter image description here

Это код, я использую для вызова 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; 
    } 
} 

Может кто-нибудь увидеть, если я делаю что-то неправильно, или если мне что-то не хватает вообще?

+2

Возможно ли зарегистрировать значение 'e' внутри внешнего блока catch? Он может содержать полезную информацию. – Nachi

+0

Несомненно, я добавлю это и посмотрю, поможет ли это – Ted

+0

Собственно, оно уже есть. e.Message записывается на выходе, то есть сообщение об ошибке u видит там ... * + ". Error =" + e.Message); * – Ted

ответ

3

Невозможно прочитать данные из транспортного соединения: Установленное соединение было прервано программным обеспечением на вашей главной машине.

Эта ошибка не имеет ничего общего с GCM API. Это означает, что ваш клиент попытался связаться с веб-службой, но соединение, которое было установлено, было отключено на одном из сетевых уровней. В зависимости от того, где вы получаете эту ошибку и сообщение об ошибке, это может означать несколько вещей.

  1. Ваш клиент решил прервать соединение из-за таймаута сокета. Увеличьте время ожидания чтения/сокета клиента, чтобы улучшить ситуацию.

  2. Балансировщик нагрузки, который находится между клиентом и сервером, сбросил соединение. Каждая сторона думает, что другая потеряла соединение.

Сетевые тайм-ауты, как правило, представляют собой огромную боль, поскольку никогда не было ясно, где было отключено соединение, и кто его бросил. Если увеличение тайм-аутов не помогает, я предлагаю отправить запросы через прокси-сервер, который может обнюхать трафик HTTPS (charles/TCPMON) или использовать Wireshark, чтобы узнать, какие пакеты удаляются.

У вашего приложения для Android также есть мониторинг GCM, который можно включить на вкладке Статистика. Проверьте, сообщает ли GCM API сообщение о состоянии, отличное от 200 OK на этом графике. Это поможет сузить проблему дальше.Если нет сообщений о кодах статуса, отличных от 200, это означает, что GCM никогда не получал ваши запросы API.

+0

Я знаю его сетевую проблему, но это не общая сетевая проблема, как я я всегда подключен к Интернету (иначе у меня не было бы подключения к внешнему миру и т. д.). Это что-то конкретное между моим сервером и gcm-серверами. И это та же проблема, если я запускаю ее на другом компьютере или локально. – Ted

+0

Вкладка Статистика? Где это? – Ted

+0

После того, как вы свяжете свой [идентификатор отправителя на консоли] (http://support.google.com/googleplay/android-developer/answer/2663268?hl=ru), вы должны увидеть статус кода ответа GCM. Перейдите в свое приложение -> Статистика -> Выберите сообщения GCM из раскрывающегося списка -> Нажмите на вкладку «Код ответа GCM». –