1. 程式人生 > >初識Netty -- 基於Netty的DayTime時間服務器

初識Netty -- 基於Netty的DayTime時間服務器

java netty

1. 關於Netty的基本認知:

JDK 1.4推出Java NIO之前,基於Java的所有Socket通信都采用的BIO(同步阻塞式IO),同步阻塞式IO存在巨大的性能和可靠性瓶頸,無法適用於高性能服務器的開發。雖然後來出現了偽異步I/O通信框架,但它僅僅是對之前I/O線程模型的一個簡單優化。

JDK 1.4之後,Java誕生了NIO,也就是引入了java.nio類庫,提供了很多進行異步I/O開發的API。隨著java NIO的發展,對於高性能的服務器開發來說,java原生NIO仍然存在許多問題,甚至出現了非常嚴重的epoll bug。另外Java原生NIO的API類庫繁雜,上手難度大,並非開發者心中理想的框架。

Netty是業界最流行的NIO框架之一,它經歷的大規模的商業應用考驗,在互聯網、大數據、網絡遊戲等眾多行業已經得到了成功商用,因此Netty逐漸成為了Java NIO編程的首選框架。技術分享


2. Netty開發環境搭建

可以使用maven自動構建java項目,本例中只需一個netty jar包,手動導入即可。

下載Netty jar包並導入Java項目中。Netty jar包到http://netty.io/ netty官網)的download頁面,本例中就使用最新的netty-4.1.16.Final,在解壓之後的文件夾中找到netty-all-4.1.16.Final.jar,路徑netty-4.1.16.Final > jar > all-in-one

技術分享

在java項目中創建lib文件夾,導入netty jar包(jar包要作為庫文件導入)。

技術分享

本例中需要創建兩個項目,分別是時間服務器和時間客戶端。

技術分享


3. 基於Netty的DayTime時間服務器與客戶端架構

DayTime服務器只需一個Server啟動類和一個業務邏輯處理類(處理客戶端請求)即可,客戶端也只需一個Client啟動類和一個業務邏輯處理類(向服務器發送請求並處理服務器響應),參考下圖。

技術分享

①TimeServer.java(服務器啟動類)源碼如下:

技術分享

--------------------------------------------------------------------------------------------------------------------

public class TimeServer {


public void bind(int port) throws Exception {

//配置服務端NIO線程組。

EventLoopGroup bossGroup = new NioEventLoopGroup();

EventLoopGroup workerGroup = new NioEventLoopGroup();


try {

ServerBootstrap serverBootstrap = new ServerBootstrap();

serverBootstrap.group(bossGroup, workerGroup)

.channel(NioServerSocketChannel.class)

.option(ChannelOption.SO_BACKLOG, 1024)

.childHandler(new ChildChannelHandler());

//綁定端口,同步等待成功。

ChannelFuture channelFuture = serverBootstrap.bind(port).sync();

//等待服務端監聽端口關閉。

channelFuture.channel().closeFuture().sync();

} finally {

//優雅退出,釋放線程池資源。

bossGroup.shutdownGracefully();

workerGroup.shutdownGracefully();

}

}

--------------------------------------------------------------------------------------------------------------------

②TimeServerHandler.java(處理客戶端請求)源碼如下:

技術分享

--------------------------------------------------------------------------------------------------------------------

public class TimeServerHandler extends ChannelInboundHandlerAdapter {

@Override

public void channelRead(ChannelHandlerContext channelHandlerContext, 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("時間服務器收到請求:" + body);

String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(

System.currentTimeMillis()).toString() : "BAD ORDER";

ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());

channelHandlerContext.write(resp);

}


@Override

public void channelReadComplete(ChannelHandlerContext channelHandlerContext)

throws Exception {

channelHandlerContext.flush();

}


@Override

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

ctx.close();

}

}

--------------------------------------------------------------------------------------------------------------------

③TimeClient.java(客戶端啟動類)源碼如下(流程與服務器啟動類類似):

技術分享

--------------------------------------------------------------------------------------------------------------------

public class TimeClient {

public void connect(int port, String host) throws Exception {

//配置客戶端NIO線程組。

EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

try {

Bootstrap bootstrap = new Bootstrap();

bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)

.option(ChannelOption.TCP_NODELAY, true)

.handler(new ChannelInitializer<SocketChannel>() {

@Override

protected void initChannel(SocketChannel socketChannel) throws Exception {

socketChannel.pipeline().addLast(new TimeClientHandler());

}

});


//發起異步連接操作。

ChannelFuture channelFuture = bootstrap.connect(host, port).sync();


//等待客戶端鏈路關閉。

channelFuture.channel().closeFuture().sync();

} finally {

//優雅推出,釋放NIO線程組。

eventLoopGroup.shutdownGracefully();

}

}


public static void main(String[] args) throws Exception {

int port = 8080;

if (args != null && args.length > 0) {

try {

port = Integer.valueOf(args[0]);

} catch (NumberFormatException e) {

//采用默認值。

}

}

new TimeClient().connect(port, "127.0.0.1");

}

}

--------------------------------------------------------------------------------------------------------------------

④TimeClientHandler.java(客戶端業務邏輯處理類)源碼如下:

技術分享

--------------------------------------------------------------------------------------------------------------------

public class TimeClientHandler extends ChannelInboundHandlerAdapter {

private static final Logger logger = Logger

.getLogger(TimeClientHandler.class.getName());


private final ByteBuf firstMessage;


public TimeClientHandler() {

byte[] request = "QUERY TIME ORDER".getBytes();

firstMessage = Unpooled.buffer(request.length);

firstMessage.writeBytes(request);

}


@Override

public void channelActive(ChannelHandlerContext ctx) {

ctx.writeAndFlush(firstMessage);

}


@Override

public void channelRead(ChannelHandlerContext ctx, Object msg)

throws Exception {

ByteBuf byteBuf = (ByteBuf) msg;

byte[] req = new byte[byteBuf.readableBytes()];

byteBuf.readBytes(req);

String body = new String(req, "UTF-8");

System.out.println("Now is:" + body);

}


@Override

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {

// 釋放資源

logger.warning("Unexpected exception from downstream : " + cause.getMessage());

ctx.close();

}

}

--------------------------------------------------------------------------------------------------------------------

4. 啟動服務器,運行客戶端

先啟動服務器,然後運行客戶端,此時服務收到客戶端的獲取時間的請求“QUERY TIME ORDER”,會在控制臺輸出。客戶端此時會接收到服務器響應消息,也就是當前服務器時間。

技術分享


本文出自 “一赫。” 博客,謝絕轉載!

初識Netty -- 基於Netty的DayTime時間服務器