Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。
client--server交互demo
server:
在server中定义线程组、配置、端口、缓存区大小等。
public class MyNettyServer {
private EventLoopGroup acceptGroup;
private EventLoopGroup dealGroup;
private ServerBootstrap bootstrap;
private int port;
public MyNettyServer(int port) {
this.port = port;
init();
}
/**
* 初始化
* 初始化线程组、服务配置
*/
private void init() {
// 初始化线程组,构建线程组的时候,如果不传递参数,则默认构建的线程组线程数是CPU核心数量。
acceptGroup = new NioEventLoopGroup();
dealGroup = new NioEventLoopGroup();
// 初始化服务的配置
bootstrap = new ServerBootstrap();
// 绑定线程组
bootstrap.group(acceptGroup, dealGroup);
// 设定通讯模式为NIO, 同步非阻塞
bootstrap.channel(NioServerSocketChannel.class);
// 设定缓冲区大小, 缓存区的单位是字节。
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
// SO_SNDBUF发送缓冲区,SO_RCVBUF接收缓冲区,SO_KEEPALIVE开启心跳监测(保证连接有效)
bootstrap.option(ChannelOption.SO_SNDBUF, 8*1024)
.option(ChannelOption.SO_RCVBUF, 8*1024)
.option(ChannelOption.SO_KEEPALIVE, true);
}
/**
* 执行监听处理逻辑
* @return
* @throws InterruptedException
*/
public ChannelFuture execAccept() throws InterruptedException {
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new MyNettyServerHandler());
}
});
// bind方法 - 绑定监听端口的。ServerBootstrap可以绑定多个监听端口。 多次调用bind方法即可
// sync - 开始监听逻辑。 返回一个ChannelFuture。 返回结果代表的是监听成功后的一个对应的未来结果
// 可以使用ChannelFuture实现后续的服务器和客户端的交互。
ChannelFuture future = bootstrap.bind(port).sync();
return future;
}
/**
* 关闭
*/
public void release() {
acceptGroup.shutdownGracefully();
dealGroup.shutdownGracefully();
}
public static void main(String[] args) {
MyNettyServer server = null;
ChannelFuture future = null;
try {
server = new MyNettyServer(8888);
future = server.execAccept();
System.out.println("server start...");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(null != future){
try {
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(null != server){
server.release();
}
}
}
}
server handler:
继承ChannelHandlerAdapter类,覆写channelRead方法,在该方法中写对应的业务逻辑。
public class MyNettyServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// ByteBuf - netty提供的类,对NIO中的ByteBuffer进行了包装,使用时不再需要去flip
ByteBuf buf = (ByteBuf)msg;
// 开辟有效长度的字节数组大小
byte[] bytes = new byte[buf.readableBytes()];
// 将缓存中的数据读取到字节数组中。
buf.readBytes(bytes);
String message = new String(bytes,"UTF-8");
System.out.println("client: " + message);
String backMsg = "server: accept your message '" + message + "'.";
// 写操作自动释放缓存,避免内存溢出问题。
ctx.writeAndFlush(Unpooled.copiedBuffer(backMsg.getBytes("UTF-8")));
}
}
client:
与server类同
public class MyNettyClient {
private EventLoopGroup dealGroup;
private Bootstrap bootstrap;
private int port;
private String host;
public MyNettyClient(String host,int port) {
this.host = host;
this.port = port;
init();
}
private void init() {
dealGroup = new NioEventLoopGroup();
bootstrap = new Bootstrap();
bootstrap.group(dealGroup);
// 设定通讯模式为NIO, 同步非阻塞
bootstrap.channel(NioSocketChannel.class);
// 设定缓冲区大小, 缓存区的单位是字节。
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
// SO_SNDBUF发送缓冲区,SO_RCVBUF接收缓冲区,SO_KEEPALIVE开启心跳监测(保证连接有效)
bootstrap.option(ChannelOption.SO_SNDBUF, 8*1024)
.option(ChannelOption.SO_RCVBUF, 8*1024)
.option(ChannelOption.SO_KEEPALIVE, true);
}
public ChannelFuture execCon() throws InterruptedException {
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new MyNettyClientHandler());
}
});
// 连接服务端
ChannelFuture future = bootstrap.connect(host, port).sync();
return future;
}
public static void main(String[] args) {
ChannelFuture future = null;
MyNettyClient client = new MyNettyClient("127.0.0.1",8888);
try {
future = client.execCon();
Scanner scan = new Scanner(System.in);
String msg = null;
while(true) {
Thread.sleep(700);
System.out.print("enter->");
msg = scan.nextLine();
if("0".equals(msg)) {
// addListener - 增加监听,当某条件满足的时候,触发监听器。
// ChannelFutureListener.CLOSE - 关闭监听器,代表ChannelFuture执行返回后,关闭连接。
future.channel().writeAndFlush(Unpooled.copiedBuffer(msg.getBytes("UTF-8")))
.addListener(ChannelFutureListener.CLOSE);
break;
}
// 写数据
future.channel().writeAndFlush(Unpooled.copiedBuffer(msg.getBytes("UTF-8")));
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(future!=null) {
try {
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(client!=null) {
client.dealGroup.shutdownGracefully();
}
}
}
}
client handler:
与server handler类同
public class MyNettyClientHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf)msg;
byte[] bytes = new byte[buf.readableBytes()];
buf.readBytes(bytes);
String message = new String(bytes,"UTF-8");
System.out.println(message);
// 用于释放缓存。避免内存溢出
ReferenceCountUtil.release(msg);
}
}