netty入门小程序
server
public class TestNettyServer {
public static void main(String[] args) {
int port = 8888 ;
try {
new TestNettyServer().bind(port);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void bind( int port) throws InterruptedException {
//reactor线程组
//用于服务端接受客户端连接
EventLoopGroup boosGroup=new NioEventLoopGroup();
//进行socketChannel 读写
EventLoopGroup workGroup=new NioEventLoopGroup();
try {
// netty 服务端启动类
ServerBootstrap serverBootstrap=new ServerBootstrap();
serverBootstrap.group(boosGroup, workGroup)
//创建服务端
.channel(NioServerSocketChannel.class)
//设置tcp参数
.option(ChannelOption.SO_BACKLOG, 1024)
//处理io事件
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//super.channelRead(ctx, msg);
ByteBuf buf = (ByteBuf)msg;
// 创建域buf中可读字节数相同大小的数组
byte[] req=new byte[buf.readableBytes()];
//将缓冲区可读字节复制到req数组中
buf.readBytes(req);
System.out.println(" the time server receiver request :" + new String(req, "utf-8"));
ByteBuf resp=Unpooled.copiedBuffer(new Date(System.currentTimeMillis()).toLocaleString().getBytes());
//写回客户端
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//super.channelReadComplete(ctx);
//刷新到缓冲数组中
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
ctx.close();
}
});
}
});
//绑定端口,同步等待
ChannelFuture future = serverBootstrap.bind(port).sync();
future.channel().closeFuture().sync();
}finally {
//释放线程池资源
boosGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
//输出
//the time server receiver request : tell me the time
client
public class TestNettyClient {
public static void main(String[] args) throws InterruptedException {
//客户端工作线程组
EventLoopGroup clienGroup=new NioEventLoopGroup();
//客户端netty服务启动
Bootstrap bootstrap=new Bootstrap();
try {
bootstrap.group(clienGroup)
//客户端通道
.channel(NioSocketChannel.class)
//设置可选参数
.option(ChannelOption.TCP_NODELAY, true)
//处理io事件
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//super.channelRead(ctx, msg);
ByteBuf buf=(ByteBuf) msg;
// 创建域buf中可读字节数相同大小的数组
byte[] req=new byte[buf.readableBytes()];
//将缓冲区可读字节复制到req数组中
buf.readBytes(req);
System.out.println(" client receive resp from server that the time is :" + new String(req, "utf-8"));
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
//发送请求
byte[] bytes=" tell me the time ".getBytes();
ByteBuf buf=Unpooled.buffer(bytes.length);
buf.writeBytes(bytes);
ctx.writeAndFlush(buf);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
ctx.close(); //异常关闭资源
}
});
}
});
ChannelFuture future=bootstrap.connect("127.0.0.1", 8888).sync();
future.channel().closeFuture().sync();
}finally {
clienGroup.shutdownGracefully();
}
}
}
//输出
//client receive resp from server that the time is :2017-7-21 0:23:54
Tcp粘包/拆包
tcp在传输数据时,可能会拆分为多个包进行发送,也可能会将多个小包合并为一个大包发送。 解决: 1.消息定长发送; 2.在包尾增加回车换车符进行分割 3.将消息分为消息头和消息体,消息头中包含表示消息总长度的字段。
server
public class TestTcpServer {
public static void main(String[] args) {
int port=8888;
try {
new TestTcpServer().bind(port);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void bind(int port) throws InterruptedException {
//reactor线程组
//用于服务端接受客户端连接
EventLoopGroup boosGroup=new NioEventLoopGroup();
//进行socketChannel 读写
EventLoopGroup workGroup=new NioEventLoopGroup();
//记录客户端请求次数
AtomicInteger atomicInteger=new AtomicInteger(0);
try {
// netty 服务端启动类
ServerBootstrap serverBootstrap=new ServerBootstrap();
serverBootstrap.group(boosGroup, workGroup)
//创建服务端
.channel(NioServerSocketChannel.class)
//设置tcp参数
.option(ChannelOption.SO_BACKLOG, 1024)
//处理io事件
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//换行解码器
socketChannel.pipeline(). addLast(new LineBasedFrameDecoder(1024));
//直接将接受对象转化为String类型
socketChannel.pipeline().addLast(new StringDecoder());
//增加处理器
socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
super.channelRead(ctx, msg);
//ByteBuf buf=(ByteBuf) msg;
创建域buf中可读字节数相同大小的数组
//byte[] req=new byte[buf.readableBytes()];
将缓冲区可读字节复制到req数组中
//buf.readBytes(req);
String req = (String)msg ;
System.out.println(" the time server receiver request :"
+ req
+" ; the count = " + atomicInteger.incrementAndGet() );
String response=new Date(System.currentTimeMillis()).toLocaleString() + System.getProperty("line.separator");
ByteBuf resp=Unpooled.copiedBuffer(response.getBytes());
//写回客户端
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//super.channelReadComplete(ctx);
//刷新到缓冲数组中
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
ctx.close();
}
});
}
});
//绑定端口,同步等待
ChannelFuture future=serverBootstrap.bind(port).sync();
future.channel().closeFuture().sync();
} finally {
//释放线程池资源
boosGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
//输出
...
the time server receiver request : tell me the time ; the count = 99
the time server receiver request : tell me the time ; the count = 100
client
public class TestTcpServer {
public static void main(String[] args) {
int port=8888;
try {
new TestTcpServer().bind(port);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void bind(int port) throws InterruptedException {
//reactor线程组
//用于服务端接受客户端连接
EventLoopGroup boosGroup=new NioEventLoopGroup();
//进行socketChannel 读写
EventLoopGroup workGroup=new NioEventLoopGroup();
//记录客户端请求次数
AtomicInteger atomicInteger=new AtomicInteger(0);
try {
// netty 服务端启动类
ServerBootstrap serverBootstrap=new ServerBootstrap();
serverBootstrap.group(boosGroup, workGroup)
//创建服务端
.channel(NioServerSocketChannel.class)
//设置tcp参数
.option(ChannelOption.SO_BACKLOG, 1024)
//处理io事件
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//换行解码器
socketChannel.pipeline(). addLast(new LineBasedFrameDecoder(1024));
//直接将接受对象转化为String类型
socketChannel.pipeline().addLast(new StringDecoder());
//增加处理器
socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
////super.channelRead(ctx, msg);
//ByteBuf buf=(ByteBuf) msg;
//// 创建域buf中可读字节数相同大小的数组
//byte[] req=new byte[buf.readableBytes()];
////将缓冲区可读字节复制到req数组中
//buf.readBytes(req);
String req = (String)msg ;
System.out.println(" the time server receiver request :"
+ req
+" ; the count = " + atomicInteger.incrementAndGet() );
String response=new Date(System.currentTimeMillis()).toLocaleString() + System.getProperty("line.separator");
ByteBuf resp=Unpooled.copiedBuffer(response.getBytes());
//写回客户端
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//super.channelReadComplete(ctx);
//刷新到缓冲数组中
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
ctx.close();
}
});
}
});
//绑定端口,同步等待
ChannelFuture future=serverBootstrap.bind(port).sync();
future.channel().closeFuture().sync();
} finally {
//释放线程池资源
boosGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
//输出
client receive resp from server that the time is :2017-7-21 15:47:33 ; count = 98
client receive resp from server that the time is :2017-7-21 15:47:33 ; count = 99
client receive resp from server that the time is :2017-7-21 15:47:33 ; count = 100