Netty概述:
1、netty是基於Java NIO的網絡應用框架,client-server框架
2、Netty是一個高性能、異步事件驅動的NIO框架,它提供了對TCP、UDP和文件傳輸的支持,
作爲一個異步NIO框架,Netty的所有IO操作都是異步非阻塞的,
通過Future-Listener機制,用戶可以方便的主動獲取或者通過通知機制獲得IO操作結果。
3、作爲當前最流行的NIO框架,Netty在互聯網領域、大數據分佈式計算領域、遊戲行業、通信行業等獲得了廣泛的應用,
一些業界著名的開源組件也基於Netty的NIO框架構建。
Netty創建步驟:
NIO通訊服務端步驟:
1、創建ServerSocketChannel,爲它配置非阻塞模式
2、綁定監聽,配置TCP參數,錄入backlog大小等
3、創建一個獨立的IO線程,用於輪詢多路複用器Selector
4、創建Selector,將之前的ServerSocketChannel註冊到Selector上,並設置監聽標識位SelectionKey.ACCEPT
5、啓動IO線程,在循環體中執行Selector.select()方法,輪詢就緒的通道
6、當輪詢到處於就緒的通道時,需要進行判斷操作位,如果是ACCEPT狀態,說明是新的客戶端介入,則調用accept方法接受新的客戶端。
7、設置新接入客戶端的一些參數,並將其通道繼續註冊到Selector之中。設置監聽標識等
8、如果輪詢的通道操作位是READ,則進行讀取,構造Buffer對象等
9、更細節的還有數據沒發送完成繼續發送的問題
.在Netty中包含下面幾個主要的組件:
Bootstrap:netty的組件容器,用於把其他各個部分連接起來;如果是TCP的Server端,則爲ServerBootstrap.
Channel:代表一個Socket的連接
EventLoopGroup:一個Group包含多個EventLoop,可以理解爲線程池
EventLoop:處理具體的Channel,一個EventLoop可以處理多個Channel
ChannelPipeline:每個Channel綁定一個pipeline,在上面註冊處理邏輯handler
Handler:具體的對消息或連接的處理,有兩種類型,Inbound和Outbound。分別代表消息接收的處理和消息發送的處理。
ChannelFuture:註解回調方法
通過輪訓監聽的方式去監聽客戶端的消息,客戶端進行編碼,服務端接收的消息進行解碼。這樣一個小例子。
創建服務端:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public void start() throws Exception {
EventLoopGroup eventLoopGroup = null;
try {
//創建ServerBootstrap實例來引導綁定和啓動服務器
ServerBootstrap serverBootstrap = new ServerBootstrap();
//創建NioEventLoopGroup對象來處理事件,如接受新連接、接收數據、寫數據等等
eventLoopGroup = new NioEventLoopGroup();
//指定通道類型爲NioServerSocketChannel,設置InetSocketAddress讓服務器監聽某個端口已等待客戶端連接。
serverBootstrap.group(eventLoopGroup).channel(NioServerSocketChannel.class).localAddress("localhost",port).childHandler(new ChannelInitializer<Channel>() {
//設置childHandler執行所有的連接請求
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new EchoServerHandler());
}
});
// 最後綁定服務器等待直到綁定完成,調用sync()方法會阻塞直到服務器完成綁定,然後服務器等待通道關閉,因爲使用sync(),所以關閉操作也會被阻塞。
ChannelFuture channelFuture = serverBootstrap.bind().sync();
System.out.println("開始監聽,端口爲:" + channelFuture.channel().localAddress());
channelFuture.channel().closeFuture().sync();
} finally {
eventLoopGroup.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
new EchoServer(20000).start();
}
}
服務端監聽器:package nio.netty.demo.EchoServer;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.Date;
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
System.out.println("server 讀取數據……");
//讀取數據
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, "UTF-8");
System.out.println("接收客戶端數據:" + body);
//向客戶端寫數據
System.out.println("server向client發送數據");
String currentTime = new Date(System.currentTimeMillis()).toString();
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("server 讀取數據完畢..");
ctx.flush();//刷新後纔將數據發出到SocketChannel
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}
客戶端創建:package nio.netty.demo.EchoServer;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
//xx
import java.net.InetSocketAddress;
//aa
public class EchoClient {
private final String host;
private final int port;
public EchoClient(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws Exception {
EventLoopGroup nioEventLoopGroup = null;
try {
//創建Bootstrap對象用來引導啓動客戶端
Bootstrap bootstrap = new Bootstrap();
//創建EventLoopGroup對象並設置到Bootstrap中,EventLoopGroup可以理解爲是一個線程池,這個線程池用來處理連接、接受數據、發送數據
nioEventLoopGroup = new NioEventLoopGroup();
//創建InetSocketAddress並設置到Bootstrap中,InetSocketAddress是指定連接的服務器地址
bootstrap.group(nioEventLoopGroup).channel(NioSocketChannel.class).remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
//添加一個ChannelHandler,客戶端成功連接服務器後就會被執行
@Override
protected void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(new EchoClientHandler());
}
});
// • 調用Bootstrap.connect()來連接服務器
ChannelFuture f = bootstrap.connect().sync();
// • 最後關閉EventLoopGroup來釋放資源
f.channel().closeFuture().sync();
} finally {
nioEventLoopGroup.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
new EchoClient("localhost", 20000).start();
}
}
客戶端監聽:package nio.netty.demo.EchoServer;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
//客戶端連接服務器後被調用
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("客戶端連接服務器,開始發送數據……");
byte[] req = "小李哥上綫了!".getBytes();
ByteBuf firstMessage = Unpooled.buffer(req.length);
firstMessage.writeBytes(req);
ctx.writeAndFlush(firstMessage);
}
//• 從服務器接收到數據後調用 監聽服務器端接受數據的狀態
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
System.out.println("client 讀取server數據..");
//服務端返回消息後
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, "UTF-8");
System.out.println("服務端數據爲 :" + body);
/*ByteBuf firstMessage = Unpooled.buffer("XXX".getBytes().length);
firstMessage.writeBytes("XXX".getBytes());
ctx.writeAndFlush(firstMessage);*/
}
//• 發生異常時被調用
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("client exceptionCaught..");
// 釋放資源
ctx.close();
}
}
服務端控制檯輸出:"C:\Program Files\Java\jdk1.8.0_111\bin\java" "-javaagent:C:\installSoft\developTools\intellij idea\IntelliJ IDEA 2017.2.4\lib\idea_rt.jar=57261:C:\installSoft\developTools\intellij idea\IntelliJ IDEA 2017.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\rt.jar;E:\mayun\rpc-svn\NettyDemo\target\classes;C:\Users\Administrator\.m2\repository\io\netty\netty-all\4.1.24.Final\netty-all-4.1.24.Final.jar" nio.netty.demo.EchoServer.EchoServer開始監聽,端口爲:/127.0.0.1:20000server 讀取數據……接收客戶端數據:小李哥上綫了!server向client發送數據server 讀取數據完畢..
客戶端控制檯輸出:
"C:\Program Files\Java\jdk1.8.0_111\bin\java" "-javaagent:C:\installSoft\developTools\intellij idea\IntelliJ IDEA 2017.2.4\lib\idea_rt.jar=57298:C:\installSoft\developTools\intellij idea\IntelliJ IDEA 2017.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\rt.jar;E:\mayun\rpc-svn\NettyDemo\target\classes;C:\Users\Administrator\.m2\repository\io\netty\netty-all\4.1.24.Final\netty-all-4.1.24.Final.jar" nio.netty.demo.EchoServer.EchoClient客戶端連接服務器,開始發送數據……client 讀取
更多免費技術資料可關注:annalin1203