Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Ruby、SSLSockets和Apple';s增强的APN消息格式_Ruby On Rails_Ruby_Sockets_Push Notification_Apple Push Notifications - Fatal编程技术网

Ruby on rails Ruby、SSLSockets和Apple';s增强的APN消息格式

Ruby on rails Ruby、SSLSockets和Apple';s增强的APN消息格式,ruby-on-rails,ruby,sockets,push-notification,apple-push-notifications,Ruby On Rails,Ruby,Sockets,Push Notification,Apple Push Notifications,我试图在Rails应用程序中实现对苹果增强推送通知消息格式的支持,但遇到了一些令人沮丧的问题。很明显,我对套接字的理解没有我想象的那么多 我的主要问题是,如果我正确发送了所有消息,我的代码将挂起,因为socket.read将在我收到消息之前被阻止。如果你的信息看起来正常,苹果不会返回任何信息,所以我的程序会锁定 下面是一些伪代码,用于说明我是如何使用它的: cert = File.read(options[:cert]) ctx = OpenSSL::SSL::SSLContext.new ct

我试图在Rails应用程序中实现对苹果增强推送通知消息格式的支持,但遇到了一些令人沮丧的问题。很明显,我对套接字的理解没有我想象的那么多

我的主要问题是,如果我正确发送了所有消息,我的代码将挂起,因为socket.read将在我收到消息之前被阻止。如果你的信息看起来正常,苹果不会返回任何信息,所以我的程序会锁定

下面是一些伪代码,用于说明我是如何使用它的:

cert = File.read(options[:cert])
ctx = OpenSSL::SSL::SSLContext.new
ctx.key = OpenSSL::PKey::RSA.new(cert, options[:passphrase])
ctx.cert = OpenSSL::X509::Certificate.new(cert)

sock = TCPSocket.new(options[:host], options[:port])
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
ssl.sync = true
ssl.connect

messages.each do |message|
  ssl.write(message.to_apn)
end

if read_buffer = ssl.read(6)
  process_error_response(read_buffer)
end
显然,这方面存在许多问题:

  • 如果我正在向大量设备发送消息,而失败消息是在处理的中途发送的,那么在我尝试向所有设备发送消息之前,我不会真正看到错误
  • 如前所述,如果苹果可以接受所有消息,我的应用程序将挂在socket read call上
  • 我试图解决这个问题的一种方法是在单独的线程中读取套接字:

    Thread.new() {
      while data = ssl.read(6)
        process_error_response(data)
      end
    }
    
    messages.each do |message|
      ssl.write(message.to_apn)
    end
    
    ssl.close
    sock.close
    
    这似乎不起作用。数据似乎从未从套接字读取。这可能是我对套接字应该如何工作的误解

    我想到的另一个解决方案是使用非阻塞读取调用。。。但在1.9之前,Ruby似乎并没有对SSLSocket进行非阻塞读取调用。。。不幸的是,我现在无法使用


    如果有人对socket编程有更好的了解,请给我指出正确的方向好吗?

    我对此也很感兴趣,这是另一种方法,不幸的是,它本身存在缺陷

    messages.each do |message|
      begin
        // Write message to APNS
        ssl.write(message.to_apn)
      rescue
        // Write failed (disconnected), read response
        response = ssl.read(6)
        // Unpack the binary response and print it out
        command, errorCode, identifier = response.unpack('CCN');
        puts "Command: #{command} Code: #{errorCode} Identifier: #{identifier}"
        // Before reconnecting, the problem (assuming incorrect token) must be solved
        break
      end
    end
    
    这似乎是可行的,因为我保持了一个持久的连接,我可以毫无问题地在
    rescue
    代码中重新连接,然后重新开始

    不过也有一些问题。我希望解决的主要问题是由于发送不正确的设备令牌(例如来自开发构建)而导致的断开连接。如果我有100个设备令牌,我发送一个消息,在中间的某个地方有一个不正确的令牌,我的代码让我知道它是哪一个(假设我提供了良好的标识符)。然后,我可以删除故障令牌,并将消息发送到故障令牌之后出现的所有设备(因为消息没有发送到它们)。但是,如果不正确的令牌位于100结尾的某个位置,则在我下次发送消息之前,
    救援
    不会发生

    问题在于代码不是实时的。如果我用这段代码向10个不正确的令牌发送10条消息,一切都会很好,循环会通过,不会报告任何问题。似乎
    write()
    并没有等到一切都清理完毕,循环会在连接终止之前运行。下一次运行循环时,
    write()
    命令失败(因为我们实际上从上次就断开了连接),我们将得到错误


    如果有其他方法来响应失败的连接,这可以解决问题。

    是否可以使用
    IO。选择
    ?它允许您指定超时,以便您可以限制阻止的时间量。有关详细信息,请参阅规范:

    cam是正确的:处理这种情况的传统方法是使用
    IO。选择

    if IO.select([ssl], nil, nil, 5)
      read_buffer = ssl.read(6)
      process_error_response(read_buffer)
    end
    

    这将检查
    ssl
    的“可读性”5秒钟,如果它可读,则返回
    ssl
    ,否则返回
    nil

    有一个简单的方法。在编写消息后,请尝试以非阻塞模式阅读:

    ssl.connect
    ssl.sync = true # then ssl.write() flushes immediately
    ssl.write(your_packed_frame)
    sleep(0.5)      # so APN have time to answer
    begin
      error_packet = ssl.read_nonblock(6) # Read one packet: 6 bytes
      # If we are here, there IS an error_packet which we need to process
    rescue  IO::WaitReadable
      # There is no (yet) 6 bytes from APN, probably everything is fine
    end
    
    我在MRI 2.1中使用它,但它也应该在早期版本中使用