Multiple iPhone APN messages, single connection
apple-push-notifications, iphone, push
Solution
Apple will silently drop your connection if it receives an invalid device token or a message that's too long. The next couple of messages after that will fail because they're just sent into the ether, essentially - the connection is closed, but the TCP window isn't exhausted.
At Urban Airship, where I work, we have a debug mode to use when people test their applications with push on our service. This will pause for a little bit after sending a message to ensure that this wasn't the issue - if the connection drops, we know it's an issue with the device token and report an error as such. A similar method might be a good way for you to check that this is, or is not, what's going on. Obviously this kills throughput and so we don't recommend it for a production environment.
Problem
I have a strange issue. I'm trying to get Apple Push Notifications working with Python. I can connect and send individual messages without a problem. The issues pop up when I start sending more than one message, but it's more bizarre than even that. I'm testing with multiple devices... some iPhones and some iPod Touches. I can send multiple messages to the iPhones without a hitch, but if I have an iPod Touch device id in the list, any message that goes after will fail. So if I send 4 messages in sequence like this: 1 - iPhone 2 - iPhone 3 - ipod Touch 4 - iPhone 1 and 2 will be delivered, 3 and 4 fail. Using the same device ID's, if I move any of the iPod Touch device ID's to be the first message, all messages will fail. Likewise, if I only send to iPhones, all messages will succeed. Here's the code I'm testing with, in it's current state, I would only get the first two messages, the last two will fail every time. ``` import struct, ssl, json, sys, time, socket, binascii from optparse import OptionParser class PushSender(object): def __init__(self, host, cert, key): self.apnhost = (host, 2195) self.sock = ssl.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM), keyfile = key, certfile = cert, do_handshake_on_connect=False) self.sock.connect(self.apnhost) while True: try: self.sock.do_handshake() break except ssl.SSLError, err: if err.args[0] == ssl.SSL_ERROR_WANT_READ: select.select([self.sock], [], []) elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: select.select([], [self.sock], []) else: raise def send_message(self, token, message): payload = {'aps':{'alert':message}} token = binascii.unhexlify(token) payloadstr = json.dumps(payload, separators=(',',':')) payloadLen = len(payloadstr) fmt = "!BH32sH%ds" % payloadLen notification = struct.pack(fmt, 0, 32, token, payloadLen, payloadstr) self.sock.write(notification) self.sock. def close(self): self.sock.close() def main(): parser = OptionParser() parser.add_option("-c", "--certificate", dest="cert", metavar="FILE", help="Certificate file", ) parser.add_option("-p", "--privatekey", dest="key", metavar="FILE", help="Key file", ) parser.add_option("--host", help="apn host", dest='host') (options, args) = parser.parse_args() sender = PushSender(options.host, options.cert, options.key) iphone1 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" print 'Sending iPhone #1 a message.' print sender.send_message(iphone1,'Hey iPhone #1.') iphone2 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" print 'Sending iPhone #2 a message.' print sender.send_message(iphone2,'Hey iPhone #2.') ipod1 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" print 'Sending iPod #1 a message.' print sender.send_message(ipod1,'Hey iPod #1.') iphone3 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" print 'Sending iPhone #3 a message.' print sender.send_message(iphone3,'Hey iPhone #3.') sender.close() if __name__=="__main__": main() ``` Any help would be appreciated...