一、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
