android - 发送 GCM 消息(服务器端)经常失败——但并非总是如此

标签 android .net http google-cloud-messaging

我正在为我的 Android 应用程序使用 Google 云消息传递 (GCM) 服务。我已经按照所有规则实现了它,并且有效。嗯,差不多。

大多数情况下,我会说在 60-70% 的情况下,我可以使用 google 网页上讨论的网络服务从我的服务器成功发送 GCM 消息。

正常情况下,我会从网络服务收到以下回复,这表明我已成功发送 GCM 消息:

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

这是在说:一切正常,消息已发送。

但是,在很多情况下,我在调用网络服务时会遇到 HTTP 错误,即:

Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.

这是告诉我调用网络服务(使用 HttpWebRequest 和 POST)失败的 .NET 消息。

这是一些显示问题的日志消息:

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;
    }
}

任何人都可以看到我是否做错了什么,或者我是否遗漏了什么?

最佳答案

Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.

此错误与 GCM API 无关。这意味着您的客户端尝试联系 Web 服务,但建立的连接已在其中一个网络层中被切断。根据您收到此错误的位置和错误消息,它可能意味着几件事。

  1. 由于套接字超时,您的客户端决定中止连接。增加客户端读取/套接字超时以改善这种情况。

  2. 位于客户端和服务器之间的负载平衡器断开了连接。每一方都认为对方断开了连接。

网络超时通常是一个巨大的痛苦,因为永远不清楚连接在哪里断开以及是谁断开的。如果增加超时没有帮助,我建议通过可以嗅探 HTTPS 流量的代理发送请求(charles/TCPMON)或使用 Wireshark 查看哪些数据包被丢弃。

您的 Android 应用程序还具有 GCM 监控功能,您可以在“统计信息”选项卡上启用该功能。检查 GCM API 是否在该图表上报告了 200 OK 以外的状态消息。这将有助于进一步缩小问题范围。如果没有除 200 以外的状态代码报告,则意味着 GCM 从未收到您的 API 请求。

关于android - 发送 GCM 消息(服务器端)经常失败——但并非总是如此,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15357577/

相关文章:

android - ORMLite 没有创建外部引用

android - 使用帐户管理器在 Android 中实现 JWT 身份验证

.net - 以编程方式强制 TextBox 值从 V 到 VM?

c# - 将禁用的 TextBox 的 ForeColor 设置为与其在 C# 中的 BackColor 相同

c# - 用于查找文本中所有关键字的高效算法

android - 减少 Google Play 商店上的应用更新大小

android - 如何从 Android 应用程序打开 youtube 应用程序

c# - 为什么 System.Net.HttpListener 创建一个新进程?

javascript - TypeError : client. getReceiver 不是 azure-iot-device-http 示例中的函数

cocoa - 使用 NSURLConnection 强制 HTTP v1.0 请求