1. 程式人生 > >Netty官方示例

Netty官方示例

不同的 har ava object keepalive amp 信息 lang nbsp

一、DEMO

官方並沒有使用Hello World來作為一個例子,而是采用RFC的DISCARD,這個協議定義了就是接收到請求後什麽也不幹。

第一步編寫DiscardServerHandler類:

package io.netty.example.discard;
 
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
//ChannelInboundHandlerAdapter實現自ChannelInboundHandler
//ChannelInboundHandler提供了不同的事件處理方法你可以重寫
public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
	/* 
	 * @說明:該方法用於接收從客戶端接收的信息
	 * @時間:2017-4-2下午12:25:05
	 * @see io.netty.channel.ChannelInboundHandlerAdapter#channelRead(io.netty.channel.ChannelHandlerContext, java.lang.Object)
	 * @param ctx
	 * @param msg
	 * @throws Exception
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg)
			throws Exception {
		//Discard the received data silently
		//ByteBuf是一個引用計數對象實現ReferenceCounted,他就是在有對象引用的時候計數+1,無的時候計數-1,當為0對象釋放內存
		ByteBuf in=(ByteBuf)msg;
		try {
			while(in.isReadable()){
				System.out.println((char)in.readByte());
				System.out.flush();
			}
		} finally {
			ReferenceCountUtil.release(msg);
		}
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
			throws Exception {
		cause.printStackTrace();
		ctx.close();
	}
}

  

第二步編寫DiscardServer:

package io.netty.example.discard;
 
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
 
public class DiscardServer {
	private int port;
	public DiscardServer(int port){
		this.port = port;
	}
	
	public void run() throws Exception{
		//Group:群組,Loop:循環,Event:事件,這幾個東西聯在一起,相比大家也大概明白它的用途了。
		//Netty內部都是通過線程在處理各種數據,EventLoopGroup就是用來管理調度他們的,註冊Channel,管理他們的生命周期。
		//NioEventLoopGroup是一個處理I/O操作的多線程事件循環
		//bossGroup作為boss,接收傳入連接
		//因為bossGroup僅接收客戶端連接,不做復雜的邏輯處理,為了盡可能減少資源的占用,取值越小越好
		EventLoopGroup bossGroup=new NioEventLoopGroup(1);
		//workerGroup作為worker,處理boss接收的連接的流量和將接收的連接註冊進入這個worker
		EventLoopGroup workerGroup=new NioEventLoopGroup();
		try {
			//ServerBootstrap負責建立服務端
			//你可以直接使用Channel去建立服務端,但是大多數情況下你無需做這種乏味的事情
			ServerBootstrap b=new ServerBootstrap();
			b.group(bossGroup, workerGroup)
			//指定使用NioServerSocketChannel產生一個Channel用來接收連接
			.channel(NioServerSocketChannel.class)
			//ChannelInitializer用於配置一個新的Channel
			//用於向你的Channel當中添加ChannelInboundHandler的實現
			.childHandler(new ChannelInitializer<SocketChannel>() {
				public void initChannel(SocketChannel ch) throws Exception {
					//ChannelPipeline用於存放管理ChannelHandel
					//ChannelHandler用於處理請求響應的業務邏輯相關代碼
					ch.pipeline().addLast(new DiscardServerHandler());
				};
			})
			//對Channel進行一些配置
			//註意以下是socket的標準參數
			//BACKLOG用於構造服務端套接字ServerSocket對象,標識當服務器請求處理線程全滿時,用於臨時存放已完成三次握手的請求的隊列的最大長度。如果未設置或所設置的值小於1,Java將使用默認值50。
			//Option是為了NioServerSocketChannel設置的,用來接收傳入連接的
			.option(ChannelOption.SO_BACKLOG, 128)
			//是否啟用心跳保活機制。在雙方TCP套接字建立連接後(即都進入ESTABLISHED狀態)並且在兩個小時左右上層沒有任何數據傳輸的情況下,這套機制才會被激活。
			//childOption是用來給父級ServerChannel之下的Channels設置參數的
			.childOption(ChannelOption.SO_KEEPALIVE, true);
			// Bind and start to accept incoming connections.
			ChannelFuture f=b.bind(port).sync();
			// Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your server.
			//sync()會同步等待連接操作結果,用戶線程將在此wait(),直到連接操作完成之後,線程被notify(),用戶代碼繼續執行
			//closeFuture()當Channel關閉時返回一個ChannelFuture,用於鏈路檢測
            f.channel().closeFuture().sync();
		}finally{
			//資源優雅釋放
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}
	
	public static void main(String[] args) {
		int port=8088;
		try {
			new DiscardServer(port).run();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

 

二、ECHO協議的DEMO

ECHO協議,定義了客戶端請求啥就返回啥

第一步編寫EchoServerHandler:

package io.netty.example.echo;
 
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
 
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
	/* 
	 * @說明:該方法用於接收從客戶端接收的信息
	 * @時間:2017-4-8下午12:08:51
	 * @see io.netty.channel.ChannelInboundHandlerAdapter#channelRead(io.netty.channel.ChannelHandlerContext, java.lang.Object)
	 * @param ctx
	 * @param msg
	 * @throws Exception
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg)
			throws Exception {
		//ChannelHandlerContext提供各種不同的操作用於觸發不同的I/O時間和操作
		//調用write方法來逐字返回接收到的信息
		//這裏我們不需要在DISCARD例子當中那樣調用釋放,因為Netty會在寫的時候自動釋放
		//只調用write是不會釋放的,它會緩存,直到調用flush
		ctx.write(msg);
		ctx.flush();
		//你可以直接使用writeAndFlush(msg)
		//ctx.writeAndFlush(msg);
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
			throws Exception {
		cause.printStackTrace();
		ctx.close();
	}
}

第二步編寫EchoServer:

package io.netty.example.echo;
 
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
 
public class EchoServer {
	private int port;
	public EchoServer(int port){
		this.port = port;
	}
	
	public void run() throws Exception{
		//NioEventLoopGroup是一個處理I/O操作的多線程事件循環
		//bossGroup作為boss,接收傳入連接
		//bossGroup只負責接收客戶端的連接,不做復雜操作,為了減少資源占用,取值越小越好
		//Group:群組,Loop:循環,Event:事件,這幾個東西聯在一起,相比大家也大概明白它的用途了。
		//Netty內部都是通過線程在處理各種數據,EventLoopGroup就是用來管理調度他們的,註冊Channel,管理他們的生命周期。
		EventLoopGroup bossGroup=new NioEventLoopGroup(1);
		//workerGroup作為worker,處理boss接收的連接的流量和將接收的連接註冊進入這個worker
		EventLoopGroup workerGroup=new NioEventLoopGroup();
		try {
			//ServerBootstrap負責建立服務端
			//你可以直接使用Channel去建立服務端,但是大多數情況下你無需做這種乏味的事情
			ServerBootstrap b=new ServerBootstrap();
			b.group(bossGroup, workerGroup)
			//指定使用NioServerSocketChannel產生一個Channel用來接收連接
			.channel(NioServerSocketChannel.class)
			//ChannelInitializer用於配置一個新的Channel
			//用於向你的Channel當中添加ChannelInboundHandler的實現
			.childHandler(new ChannelInitializer<SocketChannel>() {
				public void initChannel(SocketChannel ch) throws Exception {
					ch.pipeline().addLast(new EchoServerHandler());
				};
			})
			//對Channel進行一些配置
			//註意以下是socket的標準參數
			//BACKLOG用於構造服務端套接字ServerSocket對象,標識當服務器請求處理線程全滿時,用於臨時存放已完成三次握手的請求的隊列的最大長度。如果未設置或所設置的值小於1,Java將使用默認值50。
			//Option是為了NioServerSocketChannel設置的,用來接收傳入連接的
			.option(ChannelOption.SO_BACKLOG, 128)
			//是否啟用心跳保活機制。在雙方TCP套接字建立連接後(即都進入ESTABLISHED狀態)並且在兩個小時左右上層沒有任何數據傳輸的情況下,這套機制才會被激活。
			//childOption是用來給父級ServerChannel之下的Channels設置參數的
			.childOption(ChannelOption.SO_KEEPALIVE, true);
			// Bind and start to accept incoming connections.
			ChannelFuture f=b.bind(port).sync();
			// Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your server.
			//sync()會同步等待連接操作結果,用戶線程將在此wait(),直到連接操作完成之後,線程被notify(),用戶代碼繼續執行
			//closeFuture()當Channel關閉時返回一個ChannelFuture,用於鏈路檢測
            f.channel().closeFuture().sync();
		}finally{
			//資源優雅釋放
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}
	
	public static void main(String[] args) {
		int port=8088;
		try {
			new EchoServer(port).run();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

  

三、依賴:

<!-- Netty開始 -->
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
   <groupId>io.netty</groupId>
   <artifactId>netty-all</artifactId>
   <version>4.1.6.Final</version>
</dependency>
<!-- Netty結束 -->

 

來源:https://blog.csdn.net/wocjy/article/details/78661464

Netty官方示例