Ruby on rails Ruby、SSLSockets和Apple';s增强的APN消息格式
我试图在Rails应用程序中实现对苹果增强推送通知消息格式的支持,但遇到了一些令人沮丧的问题。很明显,我对套接字的理解没有我想象的那么多 我的主要问题是,如果我正确发送了所有消息,我的代码将挂起,因为socket.read将在我收到消息之前被阻止。如果你的信息看起来正常,苹果不会返回任何信息,所以我的程序会锁定 下面是一些伪代码,用于说明我是如何使用它的: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
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
显然,这方面存在许多问题:
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中使用它,但它也应该在早期版本中使用