ios apns netty java codec 防止粘包

简介:   ios apns java codec 防止粘包   public Bootstrap newBootstrap(Bootstrap bootstrap, final PushHandler phandler) { bootstrap.

 

ios apns java codec 防止粘包

 

 public Bootstrap newBootstrap(Bootstrap bootstrap,
            final PushHandler phandler) {
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                if (isSsl) {
                    SSLContext sslContext = SSLUtil.initSSLContext(credentials.getCertification(), credentials.getPassword());
                    SSLEngine sslEngine = sslContext.createSSLEngine();
                    sslEngine.setUseClientMode(true);
                    pipeline.addLast("ssl", new SslHandler(sslEngine));
                }
                if (Constant.debug) {
                    pipeline.addLast("log", new LoggingHandler(LogLevel.DEBUG));
                }

                pipeline.addLast("encoder", new Encoder());
                pipeline.addLast("decoder", new Decoder());
                pipeline.addLast("pushHandler", phandler);
            }
        });
        return bootstrap;
    }

 

 

 

package com.couriusby.apns.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.curiousby.apns.message.ErrorResponse;


public class Decoder extends ByteToMessageDecoder
{
	static final Logger logger = LoggerFactory.getLogger(Decoder.class);

	// 据文档: command + status + identifier = 1 + 1 + 4
	static final int responseSize = 6;

	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception
	{
		// logger.debug("readableBytes:" + in.readableBytes());
		if (in.readableBytes() >= responseSize)
		{
			ErrorResponse errorResponse = new ErrorResponse();
			errorResponse.setCommond(in.readByte());
			errorResponse.setStatus(in.readByte());
			errorResponse.setIdentifier(in.readInt());
			errorResponse.setErrorMsg(ErrorResponse.getErrorMsgByStatus(errorResponse.getStatus()));
			out.add(errorResponse);
		}
		logger.debug("decoder:" + out);
	}
}

 

package com.curiousby.apns.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

import java.nio.charset.Charset;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.curiousby.apns.message.Item;
import com.curiousby.apns.message.Notification;


/**
 * <pre>
 * 1 byte      4 byte 
 * command + frameLength + item + item + ... + item
 * 
 *         1 byte     2 byte 
 * item = itemId + itemLength + itemData
 * 
 * itemData据不同的类型有不同的长度:
 * 
 * </pre>
 * 
 * 采用组发送的方式,一次发送一系列的消息,然后每个消息的notificationIdentifier都是连续的,
 * 这样,如果apple的服务器返回错误,那么可以从错误里的Identifier知道是哪个出错了,然后重发下面的消息。
 */
public class Encoder extends MessageToByteEncoder<Notification>
{
	static final Logger logger = LoggerFactory.getLogger(Encoder.class);

	// TODO 这个到底要不要做成static的,static的可能容易调试点,不然每个线程都有一个计数的话,可能会比较乱
	// TODO 处理超出int范围,再重新从0开始的逻辑
	int identifier = 0;

	static final Charset utf8 = Charset.forName("UTF-8");

	// 据apple的文档,这个值就是2,据其它地方看到的资料,有0和1的版本。
	static final int COMMAND = 2;

	static final int defaultExpirationDate = 0;

	@Override
	protected void encode(ChannelHandlerContext ctx, Notification notification, ByteBuf out) throws Exception
	{
		// logger.debug("NotificationEncoder:" + notification);

		// String data =
		// "02000000770100205CA6A718250E1868A8EB7D8964D3E8A051B009268A3D710D0D8CC6591572890802003F7B22617073223A7B22736F756E64223A2264656661756C74222C22616C657274223A2252696E672072696E672C204E656F2E222C226261646765223A317D7D030004000000650400047FFFFFFF0500010A";
		// out.writeBytes(Hex.decodeHex(data.toCharArray()));

		out.writeByte(COMMAND);
		out.writeInt(0); // 预先写入frameLen

		int frameLenIndex = out.writerIndex();

		// 这里不检验数据格式的正确性,上层要检查

		// 开始写入items
		// 开始写入Device token
		out.writeByte(Item.DEVICE_TOKEN);
		out.writeShort(32);
		out.writeBytes(notification.getToken());

		// 写入Payload
		out.writeByte(Item.PAYLOAD);
		out.writeShort(notification.getPayload().length);
		out.writeBytes(notification.getPayload());

		// 写入Notification identifier
		out.writeByte(Item.NOTIFICATION_IDENTIFIER);
		out.writeShort(4);
		out.writeInt(notification.getId());

		// 写入Expiration date
		out.writeByte(Item.EXPIRATION_DATE);
		out.writeShort(4);
		Date expirationDate = notification.getExpirationDate();
		if (expirationDate == null)
		{
			out.writeInt(0);
		}
		else
		{
			out.writeInt((int) (expirationDate.getTime() / 1000));
		}

		// 写入Priority
		out.writeByte(Item.PRIORITY);
		out.writeShort(1);
		out.writeByte(notification.getPriority());

		// 回退到该写入frameLen的位置,写入frameLen,再重新设置write index
		int currentWriteIndex = out.writerIndex();
		out.writerIndex(1); // 因为command后面就是len,而command是1 byte。
		out.writeInt(currentWriteIndex - frameLenIndex);
		out.writerIndex(currentWriteIndex);
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

捐助开发者

在兴趣的驱动下,写一个免费的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。 当然,有钱捧个钱场(支持支付宝和微信捐助,加入it技术扣扣群),没钱捧个人场,谢谢各位。



 
 
 谢谢您的赞助,我会做的更好!

目录
相关文章
|
3月前
|
编解码 网络协议 开发者
Netty运行原理问题之NettyTCP的粘包和拆包的问题如何解决
Netty运行原理问题之NettyTCP的粘包和拆包的问题如何解决
|
18天前
|
消息中间件 缓存 Java
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
零拷贝技术 Zero-Copy 是指计算机执行操作时,可以直接从源(如文件或网络套接字)将数据传输到目标缓冲区, 而不需要 CPU 先将数据从某处内存复制到另一个特定区域,从而减少上下文切换以及 CPU 的拷贝时间。
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
|
3月前
|
微服务
成功解决:java.lang.NoSuchMethodError: reactor.netty.http.client.HttpClient.chunkedTransfer(Z)Lreactor/ne
这篇文章讲述了在微服务架构中整合gateway网关时遇到的`java.lang.NoSuchMethodError`错误的解决方法。问题主要是由于`spring-boot-starter-parent`的版本和`spring-cloud-starter-gateway`的版本不匹配所导致。文章提供了具体的版本不一致的错误配置,并给出了匹配的版本配置方案,以及成功测试的截图。
成功解决:java.lang.NoSuchMethodError: reactor.netty.http.client.HttpClient.chunkedTransfer(Z)Lreactor/ne
|
3月前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
121 0
|
3月前
|
Java 应用服务中间件 Linux
(九)Java网络编程无冕之王-这回把大名鼎鼎的Netty框架一网打尽!
现如今的开发环境中,分布式/微服务架构大行其道,而分布式/微服务的根基在于网络编程,而Netty恰恰是Java网络编程领域的无冕之王。Netty这个框架相信大家定然听说过,其在Java网络编程中的地位,好比JavaEE中的Spring。
143 3
|
3月前
|
移动开发 网络协议 算法
(十)Netty进阶篇:漫谈网络粘包、半包问题、解码器与长连接、心跳机制实战
在前面关于《Netty入门篇》的文章中,咱们已经初步对Netty这个著名的网络框架有了认知,本章的目的则是承接上文,再对Netty中的一些进阶知识进行阐述,毕竟前面的内容中,仅阐述了一些Netty的核心组件,想要真正掌握Netty框架,对于它我们应该具备更为全面的认知。
212 2
|
3月前
|
存储 网络协议 Java
【Netty 神奇之旅】Java NIO 基础全解析:从零开始玩转高效网络编程!
【8月更文挑战第24天】本文介绍了Java NIO,一种非阻塞I/O模型,极大提升了Java应用程序在网络通信中的性能。核心组件包括Buffer、Channel、Selector和SocketChannel。通过示例代码展示了如何使用Java NIO进行服务器与客户端通信。此外,还介绍了基于Java NIO的高性能网络框架Netty,以及如何用Netty构建TCP服务器和客户端。熟悉这些技术和概念对于开发高并发网络应用至关重要。
74 0
|
5月前
|
监控 网络协议 Java
Java一分钟之-Netty:高性能异步网络库
【6月更文挑战第11天】Netty是Java的高性能异步网络框架,基于NIO,以其高吞吐量、低延迟、灵活性和安全性受到青睐。常见问题包括内存泄漏、ChannelHandler滥用和异常处理不当。要规避这些问题,需正确释放ByteBuf,精简ChannelPipeline,妥善处理异常,并深入理解Netty原理。通过代码审查、遵循最佳实践和监控日志,可提升代码质量和性能。掌握Netty,打造高效网络服务。
86 2
|
4月前
|
安全 NoSQL Java
网络安全-----Redis12的Java客户端----客户端对比12,Jedis介绍,使用简单安全性不足,lettuce(官方默认)是基于Netty,支持同步,异步和响应式,并且线程是安全的,支持R
网络安全-----Redis12的Java客户端----客户端对比12,Jedis介绍,使用简单安全性不足,lettuce(官方默认)是基于Netty,支持同步,异步和响应式,并且线程是安全的,支持R
|
5月前
|
消息中间件 存储 网络协议
拼多多面试:Netty如何解决粘包问题?
粘包和拆包问题也叫做粘包和半包问题,**它是指在数据传输时,接收方未能正常读取到一条完整数据的情况(只读取了部分数据,或多读取到了另一条数据的情况)就叫做粘包或拆包问题。** 从严格意义上来说,粘包问题和拆包问题属于两个不同的问题,接下来我们分别来看。 ## 1.粘包问题 粘包问题是指在网络通信中,发送方连续发送的多个小数据包被接收方一次性接收的现象。这可能是因为底层传输层协议(如 TCP)会将多个小数据包合并成一个大的数据块进行传输,导致接收方在接收数据时一次性接收了多个数据包,造成粘连。 例如以下案例,正常情况下客户端发送了两条消息,分别为“ABC”和“DEF”,那么接收端也应该收到两
42 0
拼多多面试:Netty如何解决粘包问题?
下一篇
无影云桌面