Я пытаюсь реализовать поддержку расширенного формата сообщений push-уведомлений Apple в своем приложении Rails, и у меня возникают некоторые неприятные проблемы. Я явно не понимаю сокеты так, как я думал.
Моя основная проблема заключается в том, что если я отправляю все сообщения правильно, мой код зависает, потому что socket.read будет блокироваться, пока я не получу сообщение. Apple не возвращает ничего, если ваши сообщения выглядели нормально, поэтому моя программа блокируется.
Вот некоторый псевдокод того, как у меня это работает:
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
Очевидно, что здесь есть ряд проблем:
- Если я отправляю сообщения на большое количество устройств, а сообщение об ошибке отправляется на полпути обработки, то я не увижу ошибку до тех пор, пока не попытаюсь отправить сообщение на все устройства.
- Как упоминалось ранее, если все сообщения были приемлемы для Apple, мое приложение зависало на вызове чтения сокета.
Один из способов, которым я пытался решить эту проблему, - чтение из сокета в отдельном потоке:
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
Это не работает. Кажется, что данные никогда не читаются из сокета. Вероятно, это неправильное понимание того, как должны работать сокеты.
Другое решение, о котором я подумал, - это неблокирующий вызов чтения... но не похоже, что Ruby имеет неблокирующий вызов чтения в SSLSocket до версии 1.9... который я, к сожалению, не могу использовать прямо сейчас.
Может ли кто-нибудь, кто лучше разбирается в программировании сокетов, указать мне правильное направление?