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