Netty:
Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。
“快速”和“简单”并不用产生维护性或性能上的问题。Netty 是一个吸收了多种协议(包括FTP、SMTP、HTTP等各种二进制文本协议)的实现经验,并经过相当精心设计的项目。最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。
第一个demon:
入门例子:采用echo协议,也就是客户端发送什么服务器就返回什么,服务器核心维护两个EventLoop,分别是bossgroup和workgroup,boosgroup主要负责完成TCP的三次握手,来完成和客户端的连接,workgroup主要负责服务器端的读写操作和编解码,具体如下:
服务器:主要功能就是监听指定端口,等待客户端连接发送消息并将其消息返回给客户端。
public class EchoServer {//netty服务器主程序和客户端主程序非常相似,但也有些许区别。
private final int port;
public EchoServer(int port){//构造方法,设置服务的所监听端口
this.port = port;
}
public static void main(String[] args) throws Exception {
if(args.length !=1){
System.out.println("参数错误");
return;
}
String host = args[0];
int port = Integer.parseInt(args[0]);
new EchoServer(port).start();
}
public void start() throws Exception{
final EchoServerHandler echoServerHandler = new EchoServerHandler();//服务的业务逻辑
EventLoopGroup bossgroup = new NioEventLoopGroup();//异步线程组
EventLoopGroup workgroup = new NioEventLoopGroup();
try {
final ServerBootstrap serverBootstrap = new ServerBootstrap();//netty的服务启动简易引导类。
serverBootstrap.group(bossgroup,workgroup).channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {//匿名内部类 服务器启动会调用此类进行初始化,添加项目相关Handler.
public void initChannel(SocketChannel socketChannel) throws Exception {
// socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024));
socketChannel.pipeline().addLast(echoServerHandler);//添加业务逻辑Handler到管道pipeline中。
}
});
ChannelFuture future = serverBootstrap.bind().sync();//异步地绑定服务器; 调用sync()方法阻塞 等待直到绑定完成
future.channel().closeFuture().sync();//获取 Channel 的 CloseFuture,并 且阻塞当前线 程直到它完成
}finally {
bossgroup.shutdownGracefully();//优雅关闭
workgroup.shutdownGracefully();
}
}
}
//服务端Handler
@ChannelHandler.Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("ReadComplete");
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);//将未决消息冲刷到 远程节点,并且关 闭该 Channel
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("Read");
ByteBuf byteBuf = (ByteBuf)msg;
System.out.println("Server received:"+byteBuf.toString(CharsetUtil.UTF_8));
ctx.write(byteBuf);//将接收到的消息 写给发送者,而 不冲刷出站消息
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("exception ");
cause.printStackTrace();
ctx.close();
}
}
客户端:连接服务器并发送消息。
public class EchoClient {
private final String host;
private final int port;
public EchoClient(String host,int port){
this.host = host;
this.port = port;
}
public void start() throws Exception{
EventLoopGroup group = new NioEventLoopGroup();
try{
io.netty.bootstrap.Bootstrap bootstrap = new io.netty.bootstrap.Bootstrap();
bootstrap.group(group)//服务器所用引导类:Serverbootstrap,创建 Bootstrap
// 指定 EventLoopGroup 以 处理客户端事件;需要适 用于 NIO 的实现 适用于 NIO 传输的 Channel 类型
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host,port))//绑定连接的服务器地址
.handler(new ChannelInitializer<SocketChannel>() {//
public void initChannel(SocketChannel socketChannel) throws Exception {
//socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024));
socketChannel.pipeline().addLast(new EchoClientHandler());//客户端Handler
}
});
ChannelFuture future = bootstrap.connect().sync();//连接到远程节点,阻 塞等待直到连接完成
future.channel().closeFuture().sync();//阻塞回调函数
}finally {
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
if(args.length !=2){
System.out.println("参数错误");
return;
}
String host = args[0];
int port = Integer.parseInt(args[1]);
new EchoClient(host,port).start();
}
}
//客户端Handler
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {//连接处于活跃状态,下图有介绍
System.out.println("Client:channelActive");
ctx.writeAndFlush(Unpooled.copiedBuffer("Time", CharsetUtil.UTF_8));//给服务器发送消息
}
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
System.out.println("Client:channelRead0:"+byteBuf.toString(CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("Client:exeception");
cause.printStackTrace();
ctx.close();
}
}
测试结果:客户端给服务器发送字符串:Time,服务器接收并返回。