JavaPNS使用与吐槽

苹果平台开发的应用程序,不支持后台运行程序,所以苹果有一个推送服务在软件的一些信息推送给用户。
JAVA中,有一个开源软件,JavaPNS实现了Java平台中连接苹果服务器与推送消息的服务。但是在使用的过程中,有两点需要使用者注意一下,希望后续使用的同志们能避免我走过的覆辙。
1、一是向苹果的服务推送消息时,如果遇到无效的deviceToken,苹果会断开网络连接,而JavaPNS不会进行重连。苹果原文:
    If you send a notification and APNs finds the notification malformed or otherwise unintelligible, it returns an error-response packet prior to disconnecting. (If there is no error, APNs doesn’t return anything.) Figure 5-3 depicts the format of the error-response packet.
2、JavaPNS是一条条发送通知的,但是对于大规模发送的生产环境,显然是不可以的,建议使用批量发送。苹果原文:
The binary interface employs a plain TCP socket for binary content that is streaming in nature. For optimum performance, you should batch multiple notifications in a single transmission over the interface, either explicitly or using a TCP/IP Nagle algorithm.

对于此,我对JavaAPNS的代码进行了改动,使其支持批量发送和苹果断开重连,但是有一个问题需要大家注意一下,在正常发送的情况下,苹果是不会向Socket中写任何数据的,需要等待其读超时,this.socket.getInputStream().read(),确订推送结果的正常。通过持续的向Socket中写数据,实现批量发送,调用flush方法时,完成一次批量发送。在PushNotificationManager增加如下方法:
public List<ResponsePacket> sendNotification(List<PushedNotification> pnl) {
		logger.info(psn + "RR批量推送时消息体的大小为:" + pnl.size());
		List<ResponsePacket> failList = new ArrayList<ResponsePacket>();
		if (pnl.size() == 0) {
			return failList;
		}
		Set<Integer> sendSet = new HashSet<Integer>();
		int counter = 0;
		while (counter < pnl.size()) {
			try {
				this.socket.setSoTimeout(3000);
				this.socket.setSendBufferSize(25600);
				this.socket.setReceiveBufferSize(600);
				for (; counter < pnl.size(); counter++) {
					PushedNotification push = pnl.get(counter);
					if (sendSet.contains(push.getIdentifier())) {
						logger.warn("信息[" + push.getIdentifier() + "]已经被推送");
						continue;
					}
					byte[] bytes = getMessage(push.getDevice().getToken(), push.getPayload(), push.getIdentifier(), push);
					this.socket.getOutputStream().write(bytes);
					// 考虑到重发的问题
					// sendSet.add(push.getIdentifier());
				}
				this.socket.getOutputStream().flush();
				// 等待回馈数据,比单个发送时延时长一点,否则将无法获取到回馈数据
				this.socket.setSoTimeout(1000);

				StringBuffer allResult = new StringBuffer();
				ResponsePacket rp = new ResponsePacket();
				int readCounter = 0;
				// 处理读回写数据的异常
				try {
					logger.info(psn + "检查流数据是否可用:" + this.socket.getInputStream().available());
					byte[] sid = new byte[4];// 发送标记
					while (true) {
						int value = this.socket.getInputStream().read();
						if (value < 0) {
							break;
						}
						readCounter++;
						if (readCounter == 1) {
							rp.setCommand(value);
						}
						if (readCounter == 2) {
							rp.setStatus(value);
						}
						if (readCounter >= 3 && readCounter <= 6) {
							sid[readCounter - 3] = (byte) value;
							if (readCounter == 6) {
								rp.setIdentifier(ByteBuffer.wrap(sid).getInt());
								if (failList.contains(rp)) {
									logger.error("错误返馈数据中已经包含当前数据," + rp.getIdentifier());
								}
								failList.add(rp);
							}
						}
						allResult.append(value + "_");
					}
					this.socket.getInputStream().close();
				} catch (SocketTimeoutException ste) {
					logger.debug(psn + "消息推送成功,无任何返回!", ste);
				} catch (IOException e) {
					logger.debug(psn + "消息推送成功,关闭连接流时出错!", e);
				}
				logger.info("苹果返回的数据为:" + allResult.toString());
				if (readCounter >= 6) {
					// 找到出错的地方
					for (int i = 0; i < pnl.size(); i++) {
						PushedNotification push = pnl.get(i);
						if (push.getIdentifier() == rp.getIdentifier()) {
							counter = i + 1;
							break;
							// 从出错的地方再次发送,
						}
					}
					try {
						this.createNewSocket();
					} catch (Exception e) {
						logger.warn("连接时出错,", e);
					}
				}
			} catch (SSLHandshakeException she) {
				// 握手出错,标记不加
				logger.warn("SHE消息推送时出错,", she);
				try {
					this.createNewSocket();
				} catch (Exception e) {
					logger.warn("连接时出错,", e);
				}
			} catch (SocketException se) {
				logger.warn("SE消息推送时出错", se);
				counter++;
				try {
					this.createNewSocket();
				} catch (Exception e) {
					logger.warn("连接时出错,", e);
				}
			} catch (IOException e) {
				logger.warn("IE消息推送时出错", e);
				counter++;
			} catch (Exception e) {
				logger.warn("E消息推送时出错", e);
				counter++;
			}

			if (counter >= pnl.size()) {
				break;
			}
		}
		return failList;
	}

猜你喜欢

转载自autumnrain-zgq.iteye.com/blog/1743279