開發工具eclipse/idea(本人目前正在切換爲idea),maven插件 java
最新版的netty包maven依賴 服務器
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>5.0.0.Alpha1</version> </dependency>
功能:client端發送一個「query time order」字符串,server端接收到後返回當前服務器時間 網絡
public class TimeServer { public void bind(int port) throws Exception{ EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); ServerBootstrap b = new ServerBootstrap(); try { b.group(bossGroup,workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) .childHandler(new ChildChannelHandler()); //綁定端口,同步等待成功 ChannelFuture f = b.bind(port).sync(); f.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{ @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new TimeServerHandler()); System.out.println("server add time server handler"); } } public static void main(String[] args) throws Exception { int port = 8080; new TimeServer().bind(port); } }
TimeServer 首先建立了2個NioEventLoopGroup實例(NioEventLoopGroup是個線程組,它包含了一組NIO線程,專門用於網絡事件的處理。),一個用於服務端接收客戶端的連接,一個用於進行SokectChannel的網絡讀寫。 eclipse
ServerBootstrap是Netty用於啓動NIO服務端的輔助啓動類,group方法將兩個線程組加入到進來。接着設置建立的Channel爲NioServerSocketChannel。 異步
而後配置NioServerSocketChannel的TCP參數,最後綁定I/O事件的處理器ChildChannelHandler。 maven
f.channel().closeFuture().sync(); 方法進行阻塞,等待服務器鏈路關閉以後main函數才退出。 ide
public class TimeServerHandler extends ChannelHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf)msg; byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); String body = new String(req,"UTF-8"); System.out.println("time server receive order is :"+body); String res = "query time order".equals(body)?new Date().toString():"bad order"; ByteBuf resBuf = Unpooled.copiedBuffer(res.getBytes()); ctx.writeAndFlush(resBuf); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { System.out.println("server channel read complete……"); ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { System.out.println("server has exception :"+cause.getMessage()); ctx.close(); } }
TimeServerHandler 它用於對網絡事件進行讀寫操做,一般咱們只須要關注channelRead和exceptionCaught這兩個方法 函數
public class TimeClient { public void connect(int port,String host) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); Bootstrap b = new Bootstrap(); try { b.group(group).channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new TimeClientHandler()); System.out.println("client add time client handler"); } }); //發起異步鏈接操做 ChannelFuture f = b.connect(host,port).sync(); f.channel().closeFuture().sync(); } finally { group.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port = 8080; new TimeClient().connect(port,"127.0.0.1"); } }
首先建立客戶端處理I/O讀寫的NioEventLoopGroup線程組,而後繼續建立客戶端輔助啓動類Bootstrap,而後對其進行配置。它的Channel須要設置爲NioSocketChannel,而後添加handler。 工具
public class TimeClientHandler extends ChannelHandlerAdapter{ private final ByteBuf firstMessage; public TimeClientHandler() { byte[] res = "query time order".getBytes(); this.firstMessage = Unpooled.buffer(res.length); firstMessage.writeBytes(res); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("client channel active"); ctx.writeAndFlush(firstMessage); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf)msg; byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); System.out.println("Server time is : "+new String(req,"UTF-8")); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { System.out.println("client have exception : " + cause.getMessage()); ctx.close(); } }
這裏重點關注channelActive,channelRead和exceptionCaught這三個方法。 oop
當客戶端和服務端TCP鏈路創建成功後,Netty的線程會調用channelActive方法,發送查詢時間指令給服務端,調用ChannelHandlerContext的writeAndFlush方法將請求發送給服務端。服務端返回消息應答時,channelRead被調用。
Server端輸出
server add time server handler time server receive order is :query time order server channel read complete……
Client端輸出
client add time client handler client channel active Server time is : Wed Dec 09 16:28:53 CST 2015
參考《Netty權威指南(第二版)》