9

Android アプリに Google Cloud Messaging (GCM) サービスを使用しています。すべてのルールに従って実装しましたが、機能します。よくほとんど。

ほとんどの場合、60 ~ 70% のケースで、Google Web ページで説明されている Web サービスを使用して、サーバーから GCM メッセージを正常に送信できます。

通常、Web サービスから次の応答を受け取ります。これは、GCM メッセージを正常に送信したことを示しています。

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

これは、すべて OK、メッセージが送信されたことを示しています。

ただし、多くの場合、Web サービスを呼び出すときに次のような HTTP エラーが発生します。

トランスポート接続からデータを読み取ることができません: 確立された接続が、ホスト マシンのソフトウェアによって中止されました。

これは、Web サービスの呼び出し (HttpWebRequest と POST を使用) が失敗したことを知らせる .NET メッセージです。

これは、問題を示すいくつかのログ メッセージです。

ここに画像の説明を入力

これは、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;
    }
}

私が何か間違ったことをしているのか、それとも一般的に何かが欠けているのか、誰にもわかりますか?

4

1 に答える 1

3

トランスポート接続からデータを読み取ることができません: 確立された接続が、ホスト マシンのソフトウェアによって中止されました。

このエラーは、特に GCM API とは関係ありません。これは、クライアントが Web サービスに接続しようとしたが、確立された接続がネットワーク層の 1 つで切断されたことを意味します。このエラーが表示される場所とエラー メッセージによって、いくつかの意味が考えられます。

  1. ソケットのタイムアウトにより、クライアントが接続を中止することを決定しました。状況を改善するには、クライアントの読み取り/ソケット タイムアウトを増やします。

  2. クライアントとサーバーの間にあるロード バランサーが接続を切断しました。それぞれの当事者は、相手が接続を切断したと考えています。

接続が切断された場所と切断されたユーザーが明確にならないため、通常、ネットワーク タイムアウトは大きな問題です。タイムアウトを増やしても解決しない場合は、HTTPS トラフィック (charles / TCPMON) をスニッフィングできるプロキシ経由でリクエストを送信するか、Wireshark を使用してドロップされているパケットを確認することをお勧めします。

Android アプリには、[統計] タブで有効にできる GCM 監視もあります。GCM API がそのグラフで 200 OK 以外のステータス メッセージを報告するかどうかを確認します。これにより、問題をさらに絞り込むことができます。200 以外のステータス コードのレポートがない場合は、GCM が最初から API リクエストを受け取っていないことを意味します。

于 2013-03-20T19:11:29.033 に答える