从苹果apns的feedback服务器获取推送失败的token

在开发自己的苹果推送服务时候,要合理的控制ios设备的Token,而这个Token是由苹果服务器Apns产生的,就是每次app问Apns要Token,由苹果服务器产生的Token会记录到Apns里面,我们需要根据该Token进行制定设备的消息推送,所有Token需要我们自己去记录和管理,每个设备对应唯一的Token,而app的用户登录会有自己约束的别名,与该tokne进行关系绑定,这样按该别名进行推送,就可以找到对应的Token,进而推送到该iso设备上,对应失效的Token我们需要访问苹果的feedbackServer,拿取失效的Token,然后把本地记录的失效token进行移除。

注意事项:
1.建议和feedback服务器建立长连接,连接过于频繁有可能被当做攻击(简简单单的做一些测试时没有关系的);所有在实际开发完成后,我们基本上可以半天与feedback服务器建立一次socket连接,拿取失效的token,
2.获取的token是在上次你给你的应用发推送失败时加feedback服务的,里面会返回失败的具体时间.
3.返回的数据由三部分组成,请看下面的图:

构中包含三个部分,第一部分是一个上次发推送失败的时间戳,第二个部分是device_token的长度,第三部分就是失效的device_token

贴下PushSharp中连接feedback的代码

  1     /// <summary>
  2     /// FeedbackService
  3     /// </summary>
  4     public class FeedbackService
  5     {
  6         public FeedbackService(ApnsConfiguration configuration)
  7         {
  8             Configuration = configuration;
  9         }
 10
 11         public ApnsConfiguration Configuration { get; private set; }
 12
 13         public delegate void FeedbackReceivedDelegate(string deviceToken, DateTime timestamp);
 14         public event FeedbackReceivedDelegate FeedbackReceived;
 15
 16         public void Check()
 17         {
 18             var encoding = Encoding.ASCII;
 19
 20             var certificate = Configuration.Certificate;
 21
 22             var certificates = new X509CertificateCollection();
 23             certificates.Add(certificate);
 24
 25             var client = new TcpClient(Configuration.FeedbackHost, Configuration.FeedbackPort);
 26
 27             var stream = new SslStream(client.GetStream(), true,
 28                 (sender, cert, chain, sslErrs) => { return true; },
 29                 (sender, targetHost, localCerts, remoteCert, acceptableIssuers) => { return certificate; });
 30
 31             stream.AuthenticateAsClient(Configuration.FeedbackHost, certificates, System.Security.Authentication.SslProtocols.Tls, false);
 32
 33
 34             //Set up
 35             byte[] buffer = new byte[4096];
 36             int recd = 0;
 37             var data = new List<byte>();
 38
 39             //Get the first feedback
 40             recd = stream.Read(buffer, 0, buffer.Length);
 41
 42             //Continue while we have results and are not disposing
 43             while (recd > 0)
 44             {
 45                 // Add the received data to a list buffer to work with (easier to manipulate)
 46                 for (int i = 0; i < recd; i++)
 47                     data.Add(buffer[i]);
 48
 49                 //Process each complete notification "packet" available in the buffer
 50                 while (data.Count >= (4 + 2 + 32)) // Minimum size for a valid packet
 51                 {
 52                     var secondsBuffer = data.GetRange(0, 4).ToArray();
 53                     var tokenLengthBuffer = data.GetRange(4, 2).ToArray();
 54
 55                     // Get our seconds since epoch
 56                     // Check endianness and reverse if needed
 57                     if (BitConverter.IsLittleEndian)
 58                         Array.Reverse(secondsBuffer);
 59                     var seconds = BitConverter.ToInt32(secondsBuffer, 0);
 60
 61                     //Add seconds since 1970 to that date, in UTC
 62                     var timestamp = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(seconds);
 63
 64                     //flag to allow feedback times in UTC or local, but default is local
 65                     if (!Configuration.FeedbackTimeIsUTC)
 66                         timestamp = timestamp.ToLocalTime();
 67
 68
 69                     if (BitConverter.IsLittleEndian)
 70                         Array.Reverse(tokenLengthBuffer);
 71                     var tokenLength = BitConverter.ToInt16(tokenLengthBuffer, 0);
 72
 73                     if (data.Count >= 4 + 2 + tokenLength)
 74                     {
 75
 76                         var tokenBuffer = data.GetRange(6, tokenLength).ToArray();
 77                         // Strings shouldn‘t care about endian-ness... this shouldn‘t be reversed
 78                         //if (BitConverter.IsLittleEndian)
 79                         //    Array.Reverse (tokenBuffer);
 80                         var token = BitConverter.ToString(tokenBuffer).Replace("-", "").ToLower().Trim();
 81
 82                         // Remove what we parsed from the buffer
 83                         data.RemoveRange(0, 4 + 2 + tokenLength);
 84
 85                         // Raise the event to the consumer
 86                         var evt = FeedbackReceived;
 87                         if (evt != null)
 88                             evt(token, timestamp);
 89                     }
 90                     else
 91                     {
 92                         continue;
 93                     }
 94
 95                 }
 96
 97                 //Read the next feedback
 98                 recd = stream.Read(buffer, 0, buffer.Length);
 99             }
100
101             try
102             {
103                 stream.Close();
104                 stream.Dispose();
105             }
106             catch { }
107
108             try
109             {
110                 client.Client.Shutdown(SocketShutdown.Both);
111                 client.Client.Dispose();
112             }
113             catch { }
114
115             try { client.Close(); }
116             catch { }
117         }
118     }

下面是处理逻辑:

 1     /// <summary>
 2     /// 处理失效的Token逻辑信息
 3     /// </summary>
 4     public class TokenProvider
 5     {
 6         private FeedbackService fs = null;
 7         private int hour = 12;
 8         private string CID;
 9
10         public TokenProvider(ApnsConfiguration cf, string CID)
11         {
12             this.fs = fs = new FeedbackService(cf);
13             this.CID = CID;
14             try
15             {
16                 int hour = int.Parse(ConfigurationManager.AppSettings["ManagerTokenHour"]);//Token的控制时间
17             }
18             catch { hour = 12; }
19         }
20
21         /// <summary>
22         /// 开启处理失效的Token逻辑信息
23         /// </summary>
24         /// <param name="cf"></param>
25         public void Init()
26         {
27             try
28             {
29                 Thread thsub = new Thread(new ThreadStart(() =>
30                 {
31                     while (true)
32                     {
33                         try
34                         {
35                             fs.Check();
36                         }
37                         catch (Exception ex)
38                         {
39                             LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = " fs.Check() Error! CID=" + CID, ExInfo = ex });
40                         }
41                         Thread.Sleep(hour * 60 * 60 * 1000);
42                     }
43                 }));
44                 fs.FeedbackReceived += fs_FeedbackReceived;
45                 thsub.Start();
46                 LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = "Open TokenProvider! CID=" + CID });
47             }
48             catch (Exception ex)
49             { LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = " Open TokenProvider Error! CID=" + CID, ExInfo = ex }); }
50         }
51
52         /// <summary>
53         /// 处理失效的Token信息
54         /// </summary>
55         /// <param name="deviceToken"></param>
56         /// <param name="timestamp"></param>
57         private void fs_FeedbackReceived(string deviceToken, DateTime timestamp)
58         {
59             try
60             {
61                 p_DeleteToken p = new p_DeleteToken(deviceToken);
62                 if (p.ExecutionDelete()) {
63                     LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = "Delete lose token success >> " + deviceToken });
64                 } else {
65                     LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = "Delete lose token error >> " + deviceToken, ExInfo = null });
66                 };
67             }
68             catch (Exception ex)
69             {
70                 LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = "fs_FeedbackReceived Error! CID=" + CID, ExInfo = ex });
71             }
72         }
73     }

时间: 2024-08-01 10:41:19

从苹果apns的feedback服务器获取推送失败的token的相关文章

搭建PXE服务器,推送安装linux系统

搭建环境: 推送服务器: Ip:192.168.189.138 系统:CentOS 5.8 推送系统:RHEL 5.4 1:配置dhcpd服务. 如果没有安装dhcpd服务,请安装: # yum -y install dhcp.x86_64 # vi /etc/dhcpd.conf option domain-name "766.com";  default-lease-time 6000;   max-lease-time 11400;   authourtative;   next

Python web实时消息服务器后台推送技术方案---GoEasy

Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送速度快,代码简单易懂上手快浏览器兼容性:GoEasy推送支持websocket 和polling两种连接方式,从而可以支持IE6及其以上的所有版本,同时还支持其它浏览器诸如Firefox, Chrome, Safari 等等.支 持不同的开发语言:   GoEasy推送提供了Restful API接口,无论你的后台程序用的是哪种语言都可以通过RestfulAPI来实现后台实时推送.

C(++) web实时消息服务器后台推送技术方案---GoEasy

Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送速度快,代码简单易懂上手快浏览器兼容性:GoEasy推送支持websocket 和polling两种连接方式,从而可以支持IE6及其以上的所有版本,同时还支持其它浏览器诸如Firefox, Chrome, Safari 等等.支 持不同的开发语言:   GoEasy推送提供了Restful API接口,无论你的后台程序用的是哪种语言都可以通过RestfulAPI来实现后台实时推送.

node.js web实时消息服务器后台推送技术方案---GoEasy

Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送速度快,代码简单易懂上手快浏览器兼容性:GoEasy推送支持websocket 和polling两种连接方式,从而可以支持IE6及其以上的所有版本,同时还支持其它浏览器诸如Firefox, Chrome, Safari 等等.支 持不同的开发语言:   GoEasy推送提供了Restful API接口,无论你的后台程序用的是哪种语言都可以通过RestfulAPI来实现后台实时推送.

Websocket web实时消息服务器后台推送技术方案---GoEasy

Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送速度快,代码简单易懂上手快浏览器兼容性:GoEasy推送支持websocket 和polling两种连接方式,从而可以支持IE6及其以上的所有版本,同时还支持其它浏览器诸如Firefox, Chrome, Safari 等等.支 持不同的开发语言:   GoEasy推送提供了Restful API接口,无论你的后台程序用的是哪种语言都可以通过RestfulAPI来实现后台实时推送.

PHP web实时消息服务器后台推送技术方案---GoEasy

Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送速度快,代码简单易懂上手快浏览器兼容性:GoEasy推送支持websocket 和polling两种连接方式,从而可以支持IE6及其以上的所有版本,同时还支持其它浏览器诸如Firefox, Chrome, Safari 等等.支 持不同的开发语言:   GoEasy推送提供了Restful API接口,无论你的后台程序用的是哪种语言都可以通过RestfulAPI来实现后台实时推送.

JAVA web实时消息服务器后台推送技术方案---GoEasy

Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送速度快,代码简单易懂上手快浏览器兼容性:GoEasy推送支持websocket 和polling两种连接方式,从而可以支持IE6及其以上的所有版本,同时还支持其它浏览器诸如Firefox, Chrome, Safari 等等.支 持不同的开发语言:   GoEasy推送提供了Restful API接口,无论你的后台程序用的是哪种语言都可以通过RestfulAPI来实现后台实时推送.

Ruby web实时消息服务器后台推送技术方案---GoEasy

Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送速度快,代码简单易懂上手快浏览器兼容性:GoEasy推送支持websocket 和polling两种连接方式,从而可以支持IE6及其以上的所有版本,同时还支持其它浏览器诸如Firefox, Chrome, Safari 等等.支 持不同的开发语言:   GoEasy推送提供了Restful API接口,无论你的后台程序用的是哪种语言都可以通过RestfulAPI来实现后台实时推送.

SignalR SelfHost实时消息,集成到web中,实现服务器消息推送

先前用过两次SignalR,但是中途有段时间没弄了,今天重新弄,发现已经忘得差不多了,做个笔记! 首先创建一个控制台项目Nuget添加引用联机搜索:Microsoft.AspNet.SignalR.SelfHostMicrosoft.Owin.Cors 在Program.cs添加代码 添加一个Hub 这个hub里面我们就实现了连接时候服务器像客户端推送一条消息,客户端接收方法为receive下面我又给这个hub添加了一个send方法,客户端发送消息来的时候会把消息广播到所有客户端去,代码如下: