
一、客户端代码及关键类说明
/**
* netty5的客户端
* @author -zhengzx-
*
*/
public class ClientSocket {
public static void main(String[] args) {
//服务类
Bootstrap bootstrap = new Bootstrap();
//worker
EventLoopGroup worker = new NioEventLoopGroup();
try {
//设置线程池
bootstrap.group(worker);
//设置socket工厂
bootstrap.channel(NioSocketChannel.class);
//设置管道
bootstrap.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new ClientSocketHandler());
}
});
ChannelFuture connect = bootstrap.connect("127.0.0.1", 10101);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
while(true){
System.out.println("请输入:");
String msg = bufferedReader.readLine();
connect.channel().writeAndFlush(msg);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
worker.shutdownGracefully();
}
}
}
【1】EventLoopGroup: 客服端需要指定EvnetLoopGroup,Netty5中实例为NioEventLoopGroup:表示一个NIO的EvnetLoopGroup。
【2】ChannelType: 指定 Channel 的类型,客户端为NioSocketChannel。在Netty中,Channel是一个Socket的抽象,它为用户提供了关于Socket状态(是否连接还是断开) 以及对Socket的读写等操作。每当 Netty 建立了一个连接后, 都会有一个对应的 Channel实例。
【3】Handler: 设置数据的处理类。
public class ClientSocketHandler extends SimpleChannelInboundHandler<String>{
@Override
protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("客户端接受消息:"+msg);
}
}
【4】ChannelPipeline: 在实例化一个Channel时,必然伴随着实例化一个ChannelPipeline。
二、服务端代码及说明
【1】EventLoopGroup: 不论是服务器端还是客户端,都必须指定EventLoopGroup. 在这个例子中, 指定了NioEventLoopGroup, 表示一个NIO的EventLoopGroup, 不过服务器端需要指定两个EventLoopGroup, 一个是bossGroup, 用于处理客户端的连接请求; 另一个是workerGroup, 用于处理与各个客户端连接的IO操作。
【2】ChannelType: 指定Channel的类型. 因为是服务器端, 因此使用了NioServerSocketChannel。
【3】Handler: 设置数据的处理器。
public class ServerSocketHandler extends SimpleChannelInboundHandler<String>{
@Override
protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(msg);
//返回字符串
ctx.writeAndFlush("hi");
}
}
三、Netty5 与 Netty4/Netty3的区别
Netty4和Netty5的主要区别在于它们的版本更新以及一些新特性的添加。Netty5是对Netty3的后续版本,因此在架构上进行了一些重大调整,增加了许多新的功能和特性,使得其复杂性相较于Netty3有所增加。然而,Netty4与Netty5的设计方式相似,因此它们之间的差异并不是特别大。简而言之,Netty5提供了比Netty3更多的高级功能和新特性,而Netty4不再作为单独的版本维护,因为它与Netty5的设计和实现相类似。
netty5的复杂性相对于netty3要多一些。架构基本被重构了。所以这里主要是介绍一些属性和用法。
核心的变化主要有:
【1】支持Android,使得移动设备变的更加强大;
【2】通过Ice Cream Sandwich解决了在ADK中最著名的与NIO和SSLEngine相关的问题,且用户显然想要重用他们应用中的的编解码和处理器代码;
【3】我们决定官方支持Android(4.0及以上版本)
简化处理器层次:
【1】ChannelInboundHandler和ChannelOutboundHandler整合为ChannelHandler。ChannelHandler现在包含输入和输出的处理方法。
【2】ChannelInboundHandlerAdapter,ChannelOutboundHandlerAdapter和ChannelDuplexHandlerAdapter已被废弃,由ChannelHandlerAdapter代替。
【3】由于现在无法区分处理器handler)是输入还是输出的处理器,CombinedChannelDuplexHandler现在由ChannelHandlerAppender代替。
Channel.deregister()已被移除。不再生效和被使用。取而代之的,我们将允许Channel被充注册到不同的事件循环。
ChannelHandlerContext.attr(..) == Channel.attr(..)
Channel和ChannelHandlerContext类都实现了AttributeMap接口,使用户可以在其上关联一个或多个属性。有时会让用户感到困惑的是Channel和ChannelHandlerContext都有其自己的存储用户定义属性的容器。例如,即使你通过Channel.attr(KEY_X).set(valueX)给属性'KEY_X’赋值,你却无法通过ChannelHandlerContext.attr(KEY_X).get()方法获取到值。反之亦是如此。这种行为不仅仅令人不解而且还浪费内存。
为了解决这个问题,我们决定每个Channel内部仅保留一个map。AttributeMap总是用AttributeKey作为它的key。AttributeKey确保键的唯一性,因此每个Channel中如果存在一个以上的属性容易是多余的。只要用户把他自己的AttributeKey定义成ChannelHandler的private static final变量,就不会有出现重复key的风险。
更简单更精确的缓冲区泄漏追踪: 之前,查找缓冲区泄漏是很困难的,并且泄漏的警告信息也不是很有帮助。现在我们有了增强的泄漏报告机制,该机制会在增长超过上限时触发。
PooledByteBufAllocator成为默认的allocator: 在4.x版本中UnpooledByteBufAllocator是默认的allocator,尽管其存在某些限制。现在PooledByteBufAllocator已经广泛使用一段时间,并且我们有了增强的缓冲区泄漏追踪机制,所以是时候让PooledByteBufAllocator成为默认了。
全局唯一的Channel ID: 每个Channel现在有了全局唯一的ID,其生成的依据是:
MAC地址(EUI-48或是EUI-64),最好是全局唯一的进程ID;System#currentTimeMillis();System#nanoTime();- 随机的
32位整数,以及系列递增的32位整数;
可通过Channel.id()方法获取Channel的ID。
更灵活的线程模型: 增加了新的ChannelHandlerInvoker接口,用于使用户可以选择使用哪个线程调用事件处理方法。替代之前的在向ChannelPipeline添加ChannelHandler时指定一个EventExecutor的方式,使用该特性需要指定一个用户自定义的ChannelHandlerInvoker实现。
EmbeddedChannel的易用性: EmbeddedChannel中的readInbound()和readOutbound()方法返回专门类型的参数,因此你不必在转换他们的返回值。这可以简化你的测试用例代码。
EmbeddedChannel ch = ...;
// BEFORE:
FullHttpRequest req = (FullHttpRequest) ch.readInbound();
// AFTER:
FullHttpRequest req = ch.readInbound();
使用Executor代替ThreadFactory: 有些应用要求用户使用Executor运行他们的任务。4.x版本要求用户在创建事件循环event loop时指定ThreadFacotry,现在不再是这样了。
Class loader友好化: 一些类型,如AttributeKey对于在容器环境下运行的应用是不友好的,现在不是了。
编解码和处理器handlers:
XmlFrameDecoder支持流式的XML文档;- 二进制的
memcache协议编解码; - 支持
SPDY/3.1(也移植到了4.x版本); - 重构了
HTTP多部分的编解码;









