實現一個功能,客戶端和服務器 輪流對一個數加+1
服務器
public class Server {
public static void main(String[] args) {
NioEventLoopGroup boss=new NioEventLoopGroup(1);
NioEventLoopGroup worker=new NioEventLoopGroup(3);
try {
final ServerBootstrap server=new ServerBootstrap();
server.group(boss,worker).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ServerHandler());
}
});
ChannelFuture future = server.bind(8881).sync();
future.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}
finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
服務器handler
netty ChannelHandler 類似 spring mvc的filter,使用的是責任鏈模式,可以對客戶端傳來的數據進行層層解析,解碼等操作。
在沒有任何特殊操作下,默認傳遞在責任中的對象是ByteBuf
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {//msg 其實就是個ByteBuf 對象
ByteBuf buf=(ByteBuf) msg;
int i = buf.readInt();
System.out.println("服務器收到客戶端消息"+ctx.channel().remoteAddress()+" "+i);
ByteBuf newbuf=ctx.alloc().buffer(1024);
newbuf.writeInt(i+1);
ctx.writeAndFlush(newbuf);
buf.release();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel active");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
客戶端
public class Client {
public static void main(String[] args) {
NioEventLoopGroup boss=new NioEventLoopGroup(1);
try {
final Bootstrap client=new Bootstrap();
client.group(boss).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ClientHandler());
}
});
ChannelFuture future = client.connect("127.0.0.1",8881).sync();
future.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}
finally {
boss.shutdownGracefully();
}
}
}
客戶端handlr
public class ClientHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf=(ByteBuf)msg;
int i=buf.readInt();
System.out.println("客服端收到服務器"+ctx.channel().remoteAddress()+"---> "+i);
Thread.sleep(2000);
ByteBuf newbuf = ctx.alloc().buffer(1024);
newbuf.writeInt(i+1);
ctx.writeAndFlush(newbuf);
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("連接服務器成功");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ByteBuf buffer = ctx.alloc().buffer(1024);
buffer.writeInt(1);
ctx.writeAndFlush(buffer);
}
}
一開始很疑惑,channelRead0(ChannelHandlerContext ctx, Object msg) 方法里的msg 到底是個什么對象? 在添加其它handler之后,比如一個StringDecode,netty會自動的把ByteBuf里的字節轉String,並傳遞在Object對象中。這是Object就是一個String。 翻了下源碼,還是很清晰的 在ChannelHandlerContext 接口中有一個fireChannelRead 方法,這個方法的解釋如下 > ChannelHandlerContext fireChannelRead(java.lang.Object msg) Description copied from interface: ChannelInboundInvoker A Channel received a message. This will result in having the ChannelInboundHandler.channelRead(ChannelHandlerContext, Object) method called of the next ChannelInboundHandler contained in the ChannelPipeline of the Channel. Specified by: fireChannelRead in interface ChannelInboundInvoker
簡單來就是會調用handler 責任鏈的下一個處理類。同過fireChannelRead方法,可以給下一個責任鏈傳遞一個對象msg,這個msg會傳遞到下一個處理類的 ChannelRead方法上。例如,StringDecode把ByteBuf轉為一個String對象msg,在調用fireChannelRead(msg),就把這個String傳到下一個handler去了。
channelRead0也是同樣的意思
netty是基於nio的框架,要是理解了nio,其實操作起來也不是很費勁。