对于“
如果一个消息发送失败,比如因为 deviceToken 不合法,APNs 会在大约 500ms 后断掉链接,在断链前发送的消息也会发送失败;”的解决,JAVA写代码,真优雅!
  https://github.com/notnoop/java-apns 


    private void monitorSocket(final Socket socket) {
        logger.debug("Launching Monitoring Thread for socket {}", socket);

        Thread t = threadFactory.newThread(new Runnable() {
            final static int EXPECTED_SIZE = 6;

            @SuppressWarnings("InfiniteLoopStatement")
            @Override
            public void run() {
                logger.debug("Started monitoring thread");
                try {
                    InputStream in;
                    try {
                        in = socket.getInputStream();
                    } catch (IOException ioe) {
                        in = null;
                    }

                    byte[] bytes = new byte[EXPECTED_SIZE];
                    while (in != null && readPacket(in, bytes)) {
                        logger.debug("Error-response packet {}", Utilities.encodeHex(bytes));
                        // Quickly close socket, so we won't ever try to send push notifications
                        // using the defective socket.
                        Utilities.close(socket);

                        int command = bytes[0] & 0xFF;
                        if (command != 8) {
                            throw new IOException("Unexpected command byte " + command);
                        }
                        int statusCode = bytes[1] & 0xFF;
                        DeliveryError e = DeliveryError.ofCode(statusCode);

                        int id = Utilities.parseBytes(bytes[2], bytes[3], bytes[4], bytes[5]);

                        logger.debug("Closed connection cause={}; id={}", e, id);
                        delegate.connectionClosed(e, id);

                        Queue<ApnsNotification> tempCache = new LinkedList<ApnsNotification>();
                        ApnsNotification notification = null;
                        boolean foundNotification = false;

                        while (!cachedNotifications.isEmpty()) {
                            notification = cachedNotifications.poll();
                            logger.debug("Candidate for removal, message id {}", notification.getIdentifier());

                            if (notification.getIdentifier() == id) {
                                logger.debug("Bad message found {}", notification.getIdentifier());
                                foundNotification = true;
                                break;
                            }
                            tempCache.add(notification);
                        }

                        if (foundNotification) {
                            logger.debug("delegate.messageSendFailed, message id {}", notification.getIdentifier());
                            delegate.messageSendFailed(notification, new ApnsDeliveryErrorException(e));
                        } else {
                            cachedNotifications.addAll(tempCache);
                            int resendSize = tempCache.size();
                            logger.warn("Received error for message that wasn't in the cache...");
                            if (autoAdjustCacheLength) {
                                cacheLength = cacheLength + (resendSize / 2);
                                delegate.cacheLengthExceeded(cacheLength);
                            }
                            logger.debug("delegate.messageSendFailed, unknown id");
                            delegate.messageSendFailed(null, new ApnsDeliveryErrorException(e));
                        }

                        int resendSize = 0;

                        while (!cachedNotifications.isEmpty()) {

                            resendSize++;
                            final ApnsNotification resendNotification = cachedNotifications.poll();
                            logger.debug("Queuing for resend {}", resendNotification.getIdentifier());
                            notificationsBuffer.add(resendNotification);
                        }
                        logger.debug("resending {} notifications", resendSize);
                        delegate.notificationsResent(resendSize);

                        drainBuffer();
                    }
                    logger.debug("Monitoring input stream closed by EOF");

                } catch (IOException e) {
                    // An exception when reading the error code is non-critical, it will cause another retry
                    // sending the message. Other than providing a more stable network connection to the APNS
                    // server we can't do much about it - so let's not spam the application's error log.
                    logger.info("Exception while waiting for error code", e);
                    delegate.connectionClosed(DeliveryError.UNKNOWN, -1);
                } finally {
                    close();
                }
            }