apns推送(Python)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sinat_30755383/article/details/83061158

在我司之前,一直听说用极光推送,后来发现公司有一个C++版本的APNS推送服务,但是写得非常烂,三天两头挂,天天被上司骂,然后在全球同性交友网站上游荡了两天,发现了一个逻辑清晰的库

https://github.com/Pr0Ger/PyAPNs2

虽然git上还有很多其他的,但是个人觉得这一个逻辑远比其他的清晰,不会出现报错都不知道为什么;

建议:直接下源码到源码路径,不要pip安装,因为你可能需要进行日志添加

需要另起一个线程调用心跳(heartbeat),来保持和APNS SERVER的长连接;这里有个很容易造成误解的地方,之前同事一直误认为,心跳是为了检查长连接是否存在,其实并不是,心跳只是为了保持长连接,即使长连接断掉也并不需要去判断重连(重连的地方并不是在心跳这里)

    def _start_heartbeat(self, heartbeat_period):
        conn_ref = weakref.ref(self._connection)

        def watchdog():
            while True:
                conn = conn_ref()
                if conn is None:
                    break

                conn.ping('0' * 8)
                nowtime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                logger.debug('ping to apns...[%s]', nowtime)
                time.sleep(heartbeat_period)

        thread = Thread(target=watchdog)
        thread.setDaemon(True)
        thread.start()

 

重连的地方是在实际发送之前,举例send_notification_batch函数中就调用了connect,注意connect函数里面执行的self_connection.connect并不是实际去连接,它的第一件事是去检查socket,如果发现socket被回收了,那么才会去执行真正的重连。

 

以上两个操作保证了长连接和重连,线上效率也是还可以的。

展开阅读全文

APNs 推送原理及问题

05-17

在 iOS 平台上,大部分应用是不允许在后台运行并连接网络的。在应用没有被运行的时候,只能通过 Apple Push Notification Service (APNs) 把数据发送到终端用户。对于互联网应用,正确高效的使用 APNs 显然非常重要。rnrnJPush 为 iOS、Android 平台提供了一个统一推送消息的平台,而对 APNs 接口的封装管理是其中非常重要的一部分。本文分享一下 JPush 团队在使用 APNs 过程中碰到的问题以及我们的解决办法,以帮助应用开发者更好的理解 APNs。rnrnApple 为应用开发者提供了一个 APNs 推送接口,称为 binary interface。rnrnBinary Interface V1rnrn最初版本的 binary interface 协议如下图,这里我们称之为 v1。rnrnBinary Interface V1rnrn[img=http://blog.jpush.cn/wp-content/uploads/2013/05/Original-Binary-Protocol.jpg][/img]rnrnv1 协议有几个问题:rnrn消息是否发送成功没有明确的反馈;rn如果一个消息发送失败,比如因为 deviceToken 不合法,APNs 会在大约 500ms 后断掉链接,在断链前发送的消息也会发送失败;rn经我们验证,feedback service 只有报告应用被卸载后,造成 deviceToken 失效的错误。而不会报告 deviceToken 不合法这种类型的推送错误。rn也就是说如果我们给一批用户发消息,只要有一个 deviceToken 不合法,将会有可能造成若干个用户收不到消息。并且没办法确认哪些 deviceToken 不合法,哪些 deviceToken 需要被重发。这应该是 APNs 丢消息的一个重要的原因。rnrnBinary Interface V2rnrn经过开发者不断的向 Apple 反馈这个问题,Apple 终于推出了一个新版本的 binary interface,称为 enhanced binary interface,我们称这为 v2。rnrnBinary Interface V2rnrn[img=http://blog.jpush.cn/wp-content/uploads/2013/05/aps_binary_provider_2.jpg][/img]rnrn我们发现,在 v1 的基础上增加了两个字段:rnrnIdentifier —— 一个任意的值,用于一条消息的识别。如果发送出现问题,错误应答里会把 Identifier 带回来。rnrnExpiry —— 离线消息超时的时间,如果为0或者小于0,APNs 不会保存这条消息。rnrn和 v1 一样,如果消息发送没有问题,APNs 不会有任何返回。和 v1 不同,并且很重要的改进是,如果发送出现错误,v2 会在断链之前返回一个错误应答,带上发消息时的 Identifier 和一个错误码。rnrnerror-response packetrnrn[img=http://blog.jpush.cn/wp-content/uploads/2013/05/aps_binary_error.jpg][/img]rnrn根据这个错误应答,我们有机会找到是哪条消息发送出错,并确定哪些消息需要被重发。rnrnJPush 的解决办法rnrn为了确保每一位用户都能正确的收到消息,JPush 目前已经放弃 binary interface v1,完全采用 binary interface v2。(在我写这篇文章时,发现 Apple 已经把文档中对 binary interface v1 的描述移除,看来 Apple 也已经放弃 v1)rnrn在系统设计上,我们为每一个 APNs 链接维护 一个已发送列表,按发送的先后顺序排序。如果收到发送错误应答,根据返回的 Identifier 找到出错的消息,从该消息的下一条重新开始发送。rnrn发送队列rnrn[img=http://blog.jpush.cn/wp-content/uploads/2013/05/apns_queue.png][/img]rnrn总结rnrn为了持续提高 JPush 推送服务的质量,我们团队做了很多研究和尝试。APNs 管理模块我们最初用 C 语言实现了一个版本,后来觉得用 Erlang 实现可能更方便,所以又从头开始学习 Erlang 并重新用 Erlang 写了一个版本,目前使用效果良好。rnrn在 APNs 管理系统改造的过程中,包括 JPush 的其他模块,都大量的使用了开源的模块或者系统,为了回馈开源社区,我们准备把 APNs 管理系统的 Erlang 实现开放源码,敬请期待。 论坛

APNS推送功能失败

07-16

[13-7-16 16:14:25:366 CST] 0000004a SystemErr R javapns.communication.exceptions.KeystoreException: Keystore exception: Error in loading the keystore: Private key decryption error: (java.security.InvalidKeyException: Illegal key size)rn[13-7-16 16:14:25:373 CST] 0000004a SystemErr R at javapns.communication.KeystoreManager.wrapKeystoreException(KeystoreManager.java:178)rn[13-7-16 16:14:25:373 CST] 0000004a SystemErr R at javapns.communication.KeystoreManager.loadKeystore(KeystoreManager.java:66)rn[13-7-16 16:14:25:373 CST] 0000004a SystemErr R at javapns.communication.KeystoreManager.loadKeystore(KeystoreManager.java:42)rn[13-7-16 16:14:25:373 CST] 0000004a SystemErr R at javapns.communication.KeystoreManager.loadKeystore(KeystoreManager.java:29)rn[13-7-16 16:14:25:374 CST] 0000004a SystemErr R at javapns.communication.ConnectionToAppleServer.(ConnectionToAppleServer.java:54)rn[13-7-16 16:14:25:374 CST] 0000004a SystemErr R at javapns.notification.ConnectionToNotificationServer.(ConnectionToNotificationServer.java:16)rn[13-7-16 16:14:25:374 CST] 0000004a SystemErr R at javapns.notification.PushNotificationManager.initializeConnection(PushNotificationManager.java:105)rn[13-7-16 16:14:25:374 CST] 0000004a SystemErr R at javapns.Push.sendPayload(Push.java:171)rn[13-7-16 16:14:25:374 CST] 0000004a SystemErr R at javapns.Push.payload(Push.java:149)rn[13-7-16 16:14:25:374 CST] 0000004a SystemErr R at apps.utils.IOSSenderUtil.send(IOSSenderUtil.java:58)rn[13-7-16 16:14:25:374 CST] 0000004a SystemErr R at apps.utils.IOSSenderUtil.sendMessage(IOSSenderUtil.java:220)rn[13-7-16 16:14:25:374 CST] 0000004a SystemErr R at apps.utils.IOSSenderUtil.access$0(IOSSenderUtil.java:120)rn[13-7-16 16:14:25:374 CST] 0000004a SystemErr R at apps.utils.IOSSenderUtil$1$1.run(IOSSenderUtil.java:244)rn[13-7-16 16:14:25:374 CST] 0000004a SystemErr R at com.coactsoft.ae.transaction.TransactionInvoker.execute(Unknown Source:18)rn[13-7-16 16:14:25:375 CST] 0000004a SystemErr R at sun.reflect.GeneratedMethodAccessor843.invoke(Unknown Source)rn[13-7-16 16:14:25:375 CST] 0000004a SystemErr R at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)rn[13-7-16 16:14:25:375 CST] 0000004a SystemErr R at java.lang.reflect.Method.invoke(Method.java:618)rn[13-7-16 16:14:25:375 CST] 0000004a SystemErr R at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:304)rn[13-7-16 16:14:25:375 CST] 0000004a SystemErr R at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)rn[13-7-16 16:14:25:375 CST] 0000004a SystemErr R at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)rn[13-7-16 16:14:25:375 CST] 0000004a SystemErr R at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)rn[13-7-16 16:14:25:375 CST] 0000004a SystemErr R at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)rn[13-7-16 16:14:25:375 CST] 0000004a SystemErr R at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)rn[13-7-16 16:14:25:375 CST] 0000004a SystemErr R at $Proxy25.execute(Unknown Source)rn[13-7-16 16:14:25:375 CST] 0000004a SystemErr R at com.coactsoft.ae.web.delegate.AEWebUIDelegate.doAction(Unknown Source:257)rn[13-7-16 16:14:25:376 CST] 0000004a SystemErr R at apps.utils.IOSSenderUtil.access$1(IOSSenderUtil.java:1)rn[13-7-16 16:14:25:376 CST] 0000004a SystemErr R at apps.utils.IOSSenderUtil$1.run(IOSSenderUtil.java:242)rn[13-7-16 16:14:25:376 CST] 0000004a SystemErr R Caused by: java.io.IOException: Error in loading the keystore: Private key decryption error: (java.security.InvalidKeyException: Illegal key size)rn at com.ibm.crypto.provider.PKCS12KeyStore.engineLoad(Unknown Source)rn at java.security.KeyStore.load(KeyStore.java:1173)rn at javapns.communication.KeystoreManager.loadKeystore(KeystoreManager.java:64)rn at javapns.communication.KeystoreManager.loadKeystore(KeystoreManager.java:42)rn at javapns.communication.KeystoreManager.loadKeystore(KeystoreManager.java:29)rn at javapns.communication.ConnectionToAppleServer.(ConnectionToAppleServer.java:54)rn at javapns.notification.ConnectionToNotificationServer.(ConnectionToNotificationServer.java:16)rn at javapns.notification.PushNotificationManager.initializeConnection(PushNotificationManager.java:105)rn at javapns.Push.sendPayload(Push.java:171)rn at javapns.Push.payload(Push.java:149)rn at apps.utils.IOSSenderUtil.send(IOSSenderUtil.java:58)rn at apps.utils.IOSSenderUtil.sendMessage(IOSSenderUtil.java:220)rn at apps.utils.IOSSenderUtil.access$0(IOSSenderUtil.java:120)rn at apps.utils.IOSSenderUtil$1$1.run(IOSSenderUtil.java:244)rn at com.coactsoft.ae.transaction.TransactionInvoker.execute(Unknown Source:18)rn at sun.reflect.GeneratedMethodAccessor843.invoke(Unknown Source)rn at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)rn at java.lang.reflect.Method.invoke(Method.java:618)rn at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:304)rn at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)rn at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)rn at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)rn at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)rn at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)rn at $Proxy25.execute(Unknown Source)rn at com.coactsoft.ae.web.delegate.AEWebUIDelegate.doAction(Unknown Source:257)rn at apps.utils.IOSSenderUtil.access$1(IOSSenderUtil.java:1)rn at apps.utils.IOSSenderUtil$1.run(IOSSenderUtil.java:242) 论坛

没有更多推荐了,返回首页