二、Netty實現伺服器與客戶端完整互動連線實戰
阿新 • • 發佈:2018-11-04
本節內容是程式碼實現伺服器與客戶端完整連線過程。整體把控netty的工作流程。我們先不要被某個類,某個api的封裝深入挖掘,這樣你會踩很多坑,陷入進去而拔不出來,後面我會一一講解,原始碼剖析工作原理。這就是我個人學習技術的一種方法,深入淺出,慢慢徹底熟悉netty。我們先學會用,然後把它切分若干塊,慢慢吞噬。
程式碼實現:
詳細:
package com.zhurong.netty.test2; import com.zhurong.netty.test1.TestServerInitializer; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; /** * Description: * User: zhurong * Date: 2018-09-19 23:17 */ public class NettyServer { public static void main(String[] args) { //接收連線 EventLoopGroup bossGroup = new NioEventLoopGroup(); //連線傳送給work EventLoopGroup workerGroup = new NioEventLoopGroup(); try { System.out.println("伺服器啟動成功!"); ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class). childHandler(new NettyInitializer()); ChannelFuture channelFuture = serverBootstrap.bind(8899).sync(); channelFuture.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
package com.zhurong.netty.test2; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; /** * 此處定義客戶端和伺服器端傳遞的是字串所以用了String * Description: * User: zhurong * Date: 2018-09-19 23:30 */ public class NettyServerHandler extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { System.out.println(ctx.channel().remoteAddress()+"------>"+msg); //返回資料給客戶端,是一個非同步的操作 ctx.channel().writeAndFlush("server tell you hello"); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
package com.zhurong.netty.test2; import com.zhurong.netty.test1.TestHttpServerHandler; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.util.CharsetUtil; /** * Description: 客戶端與伺服器端連線一旦建立,這個類中方法就會被回撥 * User: zhurong * Date: 2018-09-19 21:29 */ public class NettyInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); //解碼器 pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4)); //編碼器,長度值是以二進位制的形式加進去 pipeline.addLast(new LengthFieldPrepender(4)); pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8)); pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8)); pipeline.addLast(new NettyServerHandler()); } }
package com.zhurong.netty.test2;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* Description:
* User: zhurong
* Date: 2018-09-19 23:37
*/
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup eventExecutors = new NioEventLoopGroup();
try {
System.out.println("客戶端啟動成功");
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventExecutors).channel(NioSocketChannel.class).handler(new NettyClientInitializer());
ChannelFuture channelFuture = bootstrap.connect("localhost",8899).sync();
channelFuture.channel().closeFuture().sync();
}finally {
eventExecutors.shutdownGracefully();
}
}
}
package com.zhurong.netty.test2;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* Description:
* User: zhurong
* Date: 2018-09-23 22:01
*/
public class NettyClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("收到伺服器的訊息:"+ctx.channel().remoteAddress());
System.out.println("msg:"+ msg);
// ctx.writeAndFlush("from client "+ System.currentTimeMillis());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush("客戶端第一條資訊");
}
}
package com.zhurong.netty.test2;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
/**
* Description: 客戶端與伺服器端連線一旦建立,這個類中方法就會被回撥
* User: zhurong
* Date: 2018-09-19 21:29
*/
public class NettyClientInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//解碼器
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
//編碼器,長度值是以二進位制的形式加進去
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new NettyClientHandler());
}
}