C2DM连接状态的推测方法

16

我试图估计C2DM消息是否能够被接收。

我创建了一个应用程序,依赖于在手机处于不可访问状态时向其推送信息。我了解到C2DM的投递并不是一定可靠的,但至少我想知道什么时候消息的投递是可能的;当它不可能时,我们可以使用自己的推送服务(并且可以判断何时连接成功)。

我注意到在Android上,即使没有登录Google帐户,C2DM仍然会发出身份验证令牌;即使在这种情况下已经声明不应该传递消息,但似乎仍会传递消息。如果GTalk未连接(防火墙或其他原因),请求身份验证令牌时根本没有响应。当手机处于飞行模式时,应用程序也会返回身份验证令牌。这意味着检查互联网是否可用并不像看起来那么简单。我找不到一个可靠的方法来检查GTalk是否已登录。

再次强调, 我不需要保证消息的投递,但至少我想知道投递是否可能。有人有有趣的解决方案吗?


你只是需要澄清一下,想知道在服务器端是否可以联系到手机? - Warpzit
任何一种都可以……但主要目标是能够在电话上判断是否连接,以便在必要时打开自己的TCP连接。 - Ian Elliott
据我所知,c2dm依赖于市场,因此如果您可以访问市场并且您已被验证,那么您应该是清楚的。 - Warpzit
被验证和能够主动接收消息并不是同一回事。 - Ian Elliott
8个回答

11

去看一下这个视频,它是一个有关C2DM的Google I/O讲座,介绍了如何使用以及其工作原理。据我所知,您无法知道它是否连接。大多数时候他们甚至不知道(直到他们必须发送消息并失败)。

然而,强烈建议您(在视频中也是如此)不要通过C2DM发送重要数据(因为消息可能会丢失)。该服务应仅用作“网络触发”,其占地面积应尽可能小。您的应用程序应由此触发并开始获取所需的信息本身

现在,如果您以这种方式实现它,那么实现轮询机制将变得很容易。由于你已经将“触发”与实际信息检索分开,如果没有“触发”,你可以每隔一段时间就触发检索。

您可以执行的一些操作来检查C2DM是否连接是像ping一样:

  1. 通过C2DM向手机发送消息
  2. 应用程序接收(或不接收)消息并将“pong”发送回您的服务器
  3. 服务器在标记设备为“离线”之前等待“pong”的预定时间(我会说1-2分钟)。

编辑:依赖GTalk是不可行的。 GTalk像您的应用程序一样依赖于C2DM,并没有任何“额外”的东西。此外,GTalk并不在所有设备上都存在。我不确定GTalk应用程序如何确定其是否离线(不幸的是,它不是开源的),但我猜测它只是尝试ping服务器并失败。


我已经按照你描述的做了,但我想做得更多。通过查看logcat dumps,GTalk确切地知道何时连接,并每300秒发送保持活动。但是,我无法与GTalk接口以询问它是否连接。GTalk不依赖于C2DM,而是依赖于Jabber,而C2DM消息被捆绑到XMPP规范中并通过GTalk传递。此外,如果没有GTalk,则C2DM将无法工作(这实际上我可以检测并加以考虑)。 - Ian Elliott
1
进一步检查发现它并不是真正依赖于GTalk,而是GSF...但我并不是在寻求交付的保证,只是需要一些启发式方法来确定是否可能交付。我认为谷歌不提供交付保证的原因是因为需要额外的开销来确保手机已经收到了信息。例如,没有网络连接-> 0%的交付机会。其他指标可以提高我的猜测。 - Ian Elliott
你可以在5228端口上设置一个简单的HTTP服务器(与C2DM使用相同的端口),然后尝试发送请求。不过,这似乎会带来很大的麻烦。 - Felix
需要使用TCP服务器而不是HTTP,以便更准确些,因为一些防火墙会对流量进行不同的过滤,但总体上建议很好。+1 - Ian Elliott
好的,说得对。然而据我所知(请注意这不是我的领域,我可能会错),C2DM是通过SSL完成的。当你使用SSL进行某些操作时,实际协议是无法被任何防火墙过滤的(因为它无法被读取)。在这种情况下,您可以在5228端口上设置一个HTTPS服务器,以简化事情。 - Felix
显示剩余5条评论

7
不可能。因为设备只需要验证一次,并生成注册ID并发送给第三方服务器(如您所知)。现在,一旦设备注册成功,您的工作就完成了。所以等待消息,无论是否收到消息都没有保障(因为C2DM使用UDP协议)。
备选解决方案:
虽然从Google方面直接检查是不可能的,如上所述,但如果您有任何紧急情况需要检查手机连接,则可以采取以下方法:
步骤1:创建一个Web服务来检查连接。
步骤2:从应用程序调用此Web服务,该服务将命令服务器发送推送通知以进行检查。
步骤3:现在,从服务器端,服务器将立即向特定设备(从中获取命令)发送推送通知。
步骤4:如果您收到推送通知,则意味着您仍然连接到C2DM。
这不会花费太多时间。但只有在检查连接很紧急并且用户能够处理时才遵循此方法。

我知道检查连接是不可能的,但可以看到连接是否可能。主要寻找任何可以暗示这种情况的数据。 - Ian Elliott
我认为不可能。因为在这个协议中使用的是不负责任何数据包传递保证的协议,并且它只在需要发送消息时建立连接。因此,我认为无法检查连接,因为并不总是存在连接。 - Tofeeq Ahmad

1
这可能有点天真,因为我不是一个活跃的C2DM用户,但是难道不可能读取/proc/net/netstat并查看是否有任何活动的TCP连接吗?如果没有任何连接,那么C2DM肯定无法工作。你还可以通过创建一个C2DM白名单来增加这种技术的多样性,你可以期望在其中找到特定的内容(或者说可以根据特殊的C2DM端口进行过滤吗?)

暂时还不能尝试,但很快就会了,听起来很有前途! - Ian Elliott

0

我曾经使用过C2Dm,创建了自己的推送第三方服务器。 我实现了一些基于C2DM http响应代码的逻辑,以了解是否已发送推送消息。 以下是我使用的一些代码:

int responseCode = conn.getResponseCode();

    if (responseCode == HttpServletResponse.SC_UNAUTHORIZED || responseCode == HttpServletResponse.SC_FORBIDDEN) {

        LOGGER.warn("Unauthorized - need token");

        return false;
    }

在这里,我几乎可以确定推送消息是从c2dm服务器发送的,因为我在响应中收到了一个ID:

if (responseParts[0].equals("id")) {
        LOGGER.info("Successfully sent data message to device: " + responseLine);

        return true;
    }

我已经尝试了其他方法从Google获取其他结果代码,如果您愿意,我可以将它们发布出来。希望我能对您有所帮助。


1
我在后端也在做同样的事情,但是响应中的ID仅验证了Google服务器是否收到了消息,而不是手机是否收到了消息。C2DM不提供任何交付保证。 - Ian Elliott

0

与用于传递触发器的长时间运行的C2DM连接相关的一些内容:

  • 在WLAN上,它每15分钟发送一次心跳。
  • 在移动网络上,超时时间为28分钟。

28分钟可能太长了,这取决于您的移动运营商使用的硬件、车库中的2g/3g中继器等。

您可以通过打开Google Talk服务监视器应用程序来获取有关连接的大量信息:http://www.honeytechblog.com/monitor-google-talk-service-android/

拨号:##8255##

还有一个按钮,可以立即发送心跳并重置超时时间。

如果您想确保(在客户端)可以在给定时间接收到c2dm消息,最好重新发送心跳。这可以通过编程方式完成-只能在已root的设备上完成。我可能会发布一个apk到市场,正是这样做的。


0

如果设备无法访问,即使是你的备选消息推送系统也无法工作。C2DM不能保证它会传递你的消息,但非传递事件非常罕见。对于任何其他服务也是如此。你最好的解决方法是轮询你的服务器,检查是否有任何尚未传递的新消息。我假设你的应用程序非常重要,甚至不要错过500条或1000条消息中的一条。在这种情况下,你可以实现推拉混合的方案。


我担心的事情,但这破坏了推送方法。仍然希望有一个抽象的解决方案,不涉及轮询。 - Ian Elliott
2
记住...... C2DM 的目的并不是在没有网络连接时传递消息。C2DM 的目的是允许手机自由进入睡眠状态,而不是忙碌地轮询服务器以获取活动,因为它信任 C2DM 将在发生时允许服务器唤醒手机并触发手机与服务器之间的有意通信。比喻地说,C2DM 是一个门铃(或网络中断请求的等效物),而不是一种独立的消息传递机制。它唤醒手机并让您的应用程序知道服务器上发生了有趣的事情。 - Bitbang3r

0

我认为没有办法提前确定推送尝试是否会成功,但我可以想到一种相当简单的方法来验证接收(但不能通过C2DM排队以备将来发送)——只需完成消息循环即可。

请记住,C2DM的主要优点是允许在手机睡眠和名义上离线时进行通知。一旦您的应用程序收到通知,就很难阻止您在此时唤醒手机、启动网络并发送确认。我认为您甚至不必请求“保持手机唤醒”权限,因为我相信仅仅注册C2DM通知并接收到通知的行为足以唤醒手机并允许应用程序继续正常运行(至少足够长的时间来启动网络并发送确认)。

在此过程中,您还应该跟踪那些比您预期的时间更长的确认信息。如果您看到了更多的确认信息,您可能需要修改重新发送策略。

唯一可能导致此方法失败的现实世界边缘情况是,如果您有用户费尽心思地禁用数据,同时保留语音/短信功能(我相当确定C2DM在电话轮询传入呼叫和文本消息时使用4个字节的响应数据报,最初是为RIM保留的,后来被重新用于苹果和谷歌)。

这也是我曾经有过的一个想法,但问题在于这种方法只能告诉我最后一次连接到服务器的时间。对我来说几乎没有用处,因为无法判断连接是否仍然存在而不发送另一条消息。 - Ian Elliott

0

尝试关闭所有网络连接并重新连接。如果您获得了注册ID,则可以接收消息。


即使没有网络连接,注册ID仍然会被发送...不太确定它是如何生成的,这种行为似乎很奇怪。注册应该是持久的,你不应该重新注册。 - Ian Elliott

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接