import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class EchoServer {
public void bind(int port) {
// 服务器线程组 用于网络事件的处理 一个用于服务器接收客户端的连接
// 另一个线程组用于处理SocketChannel的网络读写
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//NIO服务器端的辅助启动类 降低服务器开发难度
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) // 类似NIO中serverSocketChannel
.option(ChannelOption.SO_BACKLOG, 100) // 配置TCP参数
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter)); //自定义分隔符
ch.pipeline().addLast(new StringDecoder()); //设置字符串解码器 自动将报文转为字符串
ch.pipeline().addLast(new EchoServerHandler());
}
}
); // 最后绑定I/O事件的处理类
// 服务器启动后 绑定监听端口 同步等待成功 主要用于异步操作的通知回调 回调处理用的ChildChannelHandler
ChannelFuture f = b.bind(port).sync();
System.out.println("The time Server is start : "+port);
// 等待服务端监听端口关闭
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
// 优雅退出 释放线程池资源
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
System.out.println("服务器优雅的释放了线程资源...");
}
}
public static void main(String[] args) {
int port = 8080;
if(null != args && args.length > 0) {
try {
port = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
new EchoServer().bind(port);
}
}
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
public class EchoServerHandler extends ChannelHandlerAdapter {
private int counter = 0;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
String body = (String)msg;
System.out.println("This is "+ ++counter +" times receive client : ["+ body + "]");
body += "$_";
ByteBuf echo = Unpooled.copiedBuffer(body.getBytes());
ctx.writeAndFlush(echo);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
/**
* client 粘包问题通过LineBasedFrameDecoder、StringDecoder解决
* @author
*
*/
public class EchoClient {
/**
* 连接服务器
* @param host
* @param port
*/
public void connect(String host, int port) {
//配置客户端nio线程组
EventLoopGroup group = new NioEventLoopGroup();
try {
//客户端辅助启动类 对客户端配置
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new EchoClientHandler());
}
});
//异步链接服务器 同步等待链接成功
ChannelFuture f = b.connect(host, port).sync();
//等待链接关闭
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
group.shutdownGracefully();
System.out.println("客户端优雅的释放了线程资源...");
}
}
public static void main(String[] args) {
int port = 8080;
if(null != args && args.length > 0) {
try {
port = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
new EchoClient().connect("127.0.0.1", port);
}
}
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import java.util.logging.Logger;
/**
* Client 网络IO事件处理
* @author
*
*/
public class EchoClientHandler extends ChannelHandlerAdapter {
private static final Logger logger = Logger.getLogger(EchoClientHandler.class.getName());
private int counter;
static final String ECHO_REQ = "hi leech,welcome to Netty.$_";
public EchoClientHandler() {
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
for(int i=0; i<10; i++) {
ctx.writeAndFlush(Unpooled.copiedBuffer(ECHO_REQ.getBytes()));
}
logger.info("客户端active");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
logger.info("客户端收到服务器响应数据");
System.out.println("This is "+ ++counter + " times receive server :["+ msg + "]");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
logger.warning("Unexpected exception from downstream:"+cause.getMessage());
ctx.close();
System.out.println("客户端异常退出");
}
}