5

我有一个 ruby​​ 脚本,可以打开与 Apple 推送服务器的连接并发送所有待处理的通知。我看不出任何原因,但是当 Apple 断开我的脚本时,我得到了管道错误。我已经编写了脚本来适应这种情况,但我宁愿找出它发生的原因,这样我就可以首先避免它。

它不会在特定通知上始终断开连接。它不会在某个字节传输大小处断开连接。一切似乎都是零星的。您可以在单个连接上发送的数据传输或有效负载计数是否存在某些限制?看到人们一直打开一个连接的解决方案,我认为这不是问题。我看到 3 次通知后连接断开,我看到 14 次通知后连接断开。我从来没有见过它超过14。

有没有其他人遇到过这种类型的问题?如何处理?

4

2 回答 2

11

该问题是由向 APNS 服务器发送无效的设备令牌引起的。在这种特定情况下,它是一个开发令牌。当一个无效的设备令牌被发送到 APNS 时,它会断开套接字。这可能会引起一些麻烦,Apple 已将其作为他们将在未来更新中解决的问题。

于 2010-03-09T21:38:56.643 回答
2

我有一段时间遇到同样的问题,并做了两件事来解决它:

  1. 设置一些自动重新连接逻辑:我尝试尽可能长时间地保持连接,但 Apple 会不时断开您的连接。准备好处理这个问题。
  2. 移动到增强界面:使用简单界面(这是 APNS gem 和许多其他人使用的)错误将触发断开连接而没有任何反馈。如果您切换到增强格式,您将在每次发生某些事情时收到一个整数。错误的令牌将导致返回 8,我使用它从我的数据库中删除设备。

这是我当前的连接代码,使用 EventMachine:

module Apns

  module SocketHandler
    def initialize(wrapper)
      @wrapper = wrapper
    end

    def post_init
      start_tls(:cert_chain_file => @wrapper.pem_path,
                :private_key_file => @wrapper.rsa_path,
                :verify_peer => false)
    end

    def receive_data(data)
      @wrapper.read_data!(data)
    end

    def unbind
      @wrapper.connection_closed!
    end

    def write(data)
      begin
        send_data(data)
      rescue => exc
        @wrapper.connection_error!(exc)
      end
    end

    def close!
      close_connection
    end
  end

  class Connection
    attr_reader :pem_path, :rsa_path

    def initialize(host, port, credentials_path, monitoring, read_data_handler)
      setup_credentials(credentials_path)
      @monitoring = monitoring
      @host = host
      @port = port
      @read_data_handler = read_data_handler
      open_connection!
    end

    def write(data)
      @connection.write(data)
    end

    def open?
      @status == :open
    end

    def connection_closed!
      @status = :closed
    end

    def connection_error!(exception)
      @monitoring.inform_exception!(exception, self)
      @status = :error
    end

    def close!
      @connection.close!
    end

    def read_data!(data)
      @read_data_handler.call(data)
    end

    private
    def setup_credentials(credentials_path)
      @pem_path = "#{credentials_path}.pem"
      @rsa_path = "#{credentials_path}.rsa"
      raise ArgumentError.new("#{credentials_path}.pem and #{credentials_path}.rsa must exist!") unless (File.exists?(@pem_path) and File.exists?(@rsa_path))
    end

    def open_connection!
      @connection = EventMachine.connect(@host, @port, SocketHandler, self)
      @status = :open
    end
  end
end

结束结束

它将连接中的写入和读取分开,使用通知中的 ID 字段与我发送的相关通知以及我收到的反馈。

于 2011-12-18T12:40:58.303 回答