1.1 Netty简介
Netty是最流行的NIO框架,他的健壮性、功能、性能、可定制性和可扩展性在同类框架都是首屈一指的。它已经得到成百上千的上也项目验证,如Hadoop的RPC框架Avro、以及JMS框架,强大的RocketMQ,还有主流的分布式通信框架Dubbox等等。主要原因:简单。
Netty是基于Java NIO的网络应用框架
1.2 Netty架构组成
1.3 Netty特性
2.1 Netty初识
下载Netty包:http://netty.io/
Netty实现通信的步骤:
1、创建两个的NIO线程组,一个专门用于网络事件处理(接受客户端的连接),另一个则进行网络通信读写。
2、创建一个ServerBootstrap对象,配置Netty的一系列参数,例如接收传出数据的缓存大小等等。
3、创建一个实际处理数据的类ChannelInitializer,进行初始化的准备工作,例如设置接收传出数据的字符集、格式、已经实际处理数据的接口。
4、绑定端口,执行同步阻塞方法等待服务端启动即可。
解读netty示例:http://ifeve.com/netty5-user-guide/
代码示例:Server端
package edu.sdut.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* Server端
* @author Vision_TXG
*
*/
public class Server {
public static void main(String[] args) throws Exception {
//1、第一个线程组是用于接收Client端的接收的
EventLoopGroup bossGroup = new NioEventLoopGroup();
//2、第二个线程组是用于实际的的业务处理操作的
EventLoopGroup workerGroup = new NioEventLoopGroup();
//3、创建一个辅助类,对Server端进行一系列的配置
ServerBootstrap b = new ServerBootstrap();
//将两个线程组加入进来
b.group(bossGroup,workerGroup)
//执行使用NioServerSocketChannel类型的通道
.channel(NioServerSocketChannel.class)
//一定要使用childHandler去保定具体的事件处理器
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
sc.pipeline().addLast(new ServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG,128)
.option(ChannelOption.SO_SNDBUF, 32*1024) //设置发送缓冲大小
.option(ChannelOption.SO_RCVBUF, 32*1024) //设置接收缓冲大小
//保持连接
.childOption(ChannelOption.SO_KEEPALIVE, true);
//绑定指定的端口进行监听,可以绑定多个端口
ChannelFuture f = b.bind(8765).sync(); //异步的方法
//相当于一个阻塞的一个作用,不能让主程序停止
f.channel().closeFuture().sync();
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
ServerHandler类:
package edu.sdut.netty;
import java.util.Scanner;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;
public class ServerHandler extends ChannelHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//((ByteBuf) msg).release();
try {
//do somoeting msg
ByteBuf buf = (ByteBuf)msg;
//根据buf中的数据大小初始化byte
byte[] data = new byte[buf.readableBytes()];
//将buf中的数据读到byte中
buf.readBytes(data);
String request = new String(data,"gbk");
System.out.println("Server : " + request);
//发给客户端
String response = "I'm Server";
Scanner cin = new Scanner(System.in);
System.out.println("Server回: ");
response = cin.nextLine();
//在写的同时是有返回对象的,返回的Future类型的
ChannelFuture cf = ctx.write(Unpooled.copiedBuffer(response.getBytes()));
//只要数据发送完之后,就回主动断开连接,实现长连接和短连接
cf.addListener(ChannelFutureListener.CLOSE);
ctx.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
//读数据的时候需要释放,如果胡需要读数据就不用释放
//用完释放
ReferenceCountUtil.release(msg);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
Client端:
package edu.sdut.netty;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* Client端
* @author Vision_TXG
*
*/
public class Client {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
sc.pipeline().addLast(new ClientHandler());
}
});
//非阻塞的异步通道
ChannelFuture cf1 = b.connect("127.0.0.1",8765).sync();
//Unpooled.copiedBuffer("I'm String".getBytes())的作用是将字符串转换为字节数组
//客户端进行写数据
cf1.channel().write(Unpooled.copiedBuffer("I'm String".getBytes()));
cf1.channel().flush();
cf1.channel().closeFuture().sync();
group.shutdownGracefully();
}
}
ClientHandler类:
package edu.sdut.netty;
import java.util.Scanner;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;
public class ClientHandler extends ChannelHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//((ByteBuf) msg).release();
try {
//do somoeting msg
ByteBuf buf = (ByteBuf)msg;
//根据buf中的数据大小初始化byte
byte[] data = new byte[buf.readableBytes()];
//将buf中的数据读到byte中
buf.readBytes(data);
String response = new String(data,"gbk");
System.out.println("Client : " + response);
//发给服务器
String res = "I'm Client";
Scanner cin = new Scanner(System.in);
System.out.println("Client回: ");
res = cin.nextLine();
ctx.write(Unpooled.copiedBuffer(res.getBytes()));
ctx.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
//用完释放
ReferenceCountUtil.release(msg);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}