[翻译]Go语言开发苹果推送通知

原文在此:http://bravenewmethod.wordpress.com/2011/02/25/apple-push-notifications-with-go-language/

前两天正巧看到 APNS 没有 Go 的实现,还在琢磨怎么实现一个试试,这下我又省心了。文章本身并不怎么出色,代码倒是有些用途。翻译这篇东西纯粹是为了给自己后面的工作留个资料。大家有用则用,无用就无视吧。

————–翻译分割线————–

Go语言开发苹果推送通知

我开始尝试学习并熟悉 Go 语言,并且做了一些普通的常识,例如,发送苹果推送通知(Apple Push Notifications)。这是我个人对一些开发环境的性能测试。迄今为止,已经有:

第一步 准备

获取并编译 Go。这里的例子是在 Ubuntu 10.04 LTS x64 上,基于 Go 上手指南(Go getting started guide) 里的介绍进行安装。

  • 关于苹果推送和取得应用沙盒私钥的 .pem 文件的介绍在这里
  • 当然,你必须从 iOS 应用获取 32 位的推送令牌(push token)。

第二部 代码

这里是完整的代码,复制并保存为文件 apn.go。

注意修改证书文件(cert.pem 和 key-noenc.pem)为你自己的证书文件。同时,替换推送令牌为你自己的推送令牌, 在这个例子里为了更加清楚,使用十六进制字符串书写。

<br />
package main</p>
<p>import (<br />
   &quot;crypto/tls&quot;<br />
   &quot;fmt&quot;<br />
   &quot;net&quot;<br />
   &quot;json&quot;<br />
   &quot;os&quot;<br />
   &quot;time&quot;<br />
   &quot;bytes&quot;<br />
   &quot;encoding/hex&quot;<br />
   &quot;encoding/binary&quot;<br />
)</p>
<p>func main() {</p>
<p>   // 加载证书和配置文件<br />
   cert, err := tls.LoadX509KeyPair(&quot;cert.pem&quot;, &quot;key-noenc.pem&quot;)<br />
   if err != nil {<br />
       fmt.Printf(&quot;error: %s\n&quot;, err.String())<br />
       os.Exit(1)<br />
   }<br />
   conf := &amp;tls.Config {<br />
        Certificates: []tls.Certificate{cert},<br />
   }</p>
<p>   // 连接到 APNS 并且用 tls 客户端加密 socket<br />
   conn, err := net.Dial(&quot;tcp&quot;, &quot;&quot;, &quot;gateway.sandbox.push.apple.com:2195&quot;)<br />
   if err != nil {<br />
      fmt.Printf(&quot;tcp error: %s\n&quot;, err.String())<br />
      os.Exit(1)<br />
   }<br />
   tlsconn := tls.Client(conn, conf)</p>
<p>   // 强制握手,以验证身份握手被处理,否则会在第一次读写的时候进行尝试<br />
   err = tlsconn.Handshake()<br />
   if err != nil {<br />
      fmt.Printf(&quot;tls error: %s\n&quot;, err.String())<br />
      os.Exit(1)<br />
   }<br />
   // 调试信息<br />
   state := tlsconn.ConnectionState()<br />
   fmt.Printf(&quot;conn state %v\n&quot;, state)</p>
<p>   // 从 JSON 结构构造二进制的 payload<br />
   payload := make(map[string]interface{})<br />
   payload[&quot;aps&quot;] = map[string]string{&quot;alert&quot;: &quot;Hello Push&quot;}<br />
   bpayload, err := json.Marshal(payload)</p>
<p>   // 将十六进制的设备令牌转为二进制的字节数组<br />
   btoken, _ := hex.DecodeString(&quot;6b4628de9317c80edd1c791640b58fdfc46d21d0d2d1351687239c44d8e30ab1&quot;)</p>
<p>   // 构造 pdu<br />
   buffer := bytes.NewBuffer([]byte{})<br />
   // 命令<br />
   binary.Write(buffer, binary.BigEndian, uint8(1))</p>
<p>   // 传输 id,optional<br />
   binary.Write(buffer, binary.BigEndian, uint32(1))</p>
<p>   // 过期时间,1小时<br />
   binary.Write(buffer, binary.BigEndian, uint32(time.Seconds() + 60*60))</p>
<p>   // 推送设备令牌<br />
   binary.Write(buffer, binary.BigEndian, uint16(len(btoken)))<br />
   binary.Write(buffer, binary.BigEndian, btoken)</p>
<p>   // 推送 payload<br />
   binary.Write(buffer, binary.BigEndian, uint16(len(bpayload)))<br />
   binary.Write(buffer, binary.BigEndian, bpayload)<br />
   pdu := buffer.Bytes()</p>
<p>   // 写入 pdu<br />
   _, err = tlsconn.Write(pdu)<br />
   if err != nil {<br />
      fmt.Printf(&quot;write error: %s\n&quot;, err.String())<br />
      os.Exit(1)<br />
   }</p>
<p>   // 等待 5 秒,以便 pdu 从 socket 返回错误<br />
   tlsconn.SetReadTimeout(5*1E9)</p>
<p>   readb := [6]byte{}<br />
   n, err := tlsconn.Read(readb[:])<br />
   if n &gt; 0 {<br />
     fmt.Printf(&quot;received: %s\n&quot;, hex.EncodeToString(readb[:n]))<br />
   }</p>
<p>   tlsconn.Close()<br />
}<br />

第三步 编译和运行

简单

<br />
$ 6g apn.go<br />
$ 6l apn.6<br />
$ ./6.out<br />
conn state {true 47}<br />
$<br />

如果所有都没有问题,程序会在几秒钟后退出,你会在你的 iPhone 上看到推送通知。

3 thoughts on “[翻译]Go语言开发苹果推送通知”

  1. 对你相当无言 快点看看哪些分布式比较好用组件分享出来吧

  2. When I originally commented I clicked the “Notify me when new comments are added” checkbox and
    now each time a comment is added I get several e-mails with the same comment.
    Is there any way you can remove me from that service? Cheers!

    Take a look at my web-site … Hung

Leave a Reply

Your email address will not be published. Required fields are marked *