http://cxytiandi.com/blog/detail/17345
Netty介紹
Netty是由JBOSS提供的一個java開源框架。Netty提供異步的、事件驅動的網絡應用程序框架和工具,用以快速開發高性能、高可靠性的網絡服務器和客戶端程序。
也就是說,Netty 是一個基於NIO的客戶、服務器端編程框架,使用Netty 可以確保你快速和簡單的開發出一個網絡應用,例如實現了某種協議的客戶,服務端應用。Netty相當簡化和流線化了網絡應用的編程開發過程,例如,TCP和UDP的socket服務開發。
官網地址:http://netty.io/
使用場景
Netty之所以能成為主流的NIO框架,是因為它有下面的優點:
- NIO的類庫和API使用難度較高,Netty進行了封裝,容易上手
- 高性能,功能強大,支持多種編解碼功能,支持多種主流協議
- 成熟,穩定,已經在多個大型框架中使用(dubbo,RocketMQ,Hadoop,mycat,Spring5)
- …..
在幾年之前我上家公司用的是Mina來開發一個IM的系統,Mina也是一個很好的框架(http://mina.apache.org/)。
如今很多的框架都改成用Netty來做底層通訊了,我司現在還有一個代理框架用Mina寫的,等把Netty玩遛了可以重構了。
不知道大家看完了上面的介紹是不是已經知道Netty能用在什么場景了,下面我結合一個我之前做過的事情來進行詳細的說明,當然只是使用場景的一方面而已。
之前做抓取的時候,有一些小型的網站,頁面結構比較復雜,還需要登錄等操作,這種就不能用統一的抓取系統去抓取,只能通過寫腳本的方式針對具體的網站做抓取,抓取必備的一個條件就是代理IP,為了方便抓取,特意封裝了一個抓取的SDK,提供了抓取的方法,內置了切換代理。
我們有一個代理池服務,通過一個網址去獲取能使用的代理IP,在剛開始用的Http請求去獲取代理IP,由於抓取量比較大,通過Http請求去獲取代理IP效率不行,后面用Netty改造了獲取IP這部分,通過Netty來獲取數據,解決了實時獲取的性能問題。
通過長連接的方式,避免了Http請求每次都要建立連接帶來的性能消耗問題,通過二進制的數據傳輸減少網絡開銷,性能更高。
簡單入門
我們編寫一個服務端和客戶端,客戶端往服務端發送一條消息,消息傳輸先用字符串進行傳遞,服務端收到客戶端發送的消息,然后回復一條消息。
首先編寫服務端代碼:
public class ImServer {public void run(int port) {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast("decoder", new StringDecoder());ch.pipeline().addLast("encoder", new StringEncoder());ch.pipeline().addLast(new ServerStringHandler());}}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);try {ChannelFuture f = bootstrap.bind(port).sync();f.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}}
- 通過ServerBootstrap 進行服務的配置,和socket的參數可以通過ServerBootstrap進行設置。
- 通過group方法關聯了兩個線程組,NioEventLoopGroup是用來處理I/O操作的線程池,第一個稱為“boss”,用來accept客戶端連接,第二個稱為“worker”,處理客戶端數據的讀寫操作。當然你也可以只用一個NioEventLoopGroup同時來處理連接和讀寫,bootstrap.group()方法支持一個參數。
- channel指定NIO方式
- childHandler用來配置具體的數據處理方式 ,可以指定編解碼器,處理數據的Handler
- 綁定端口啟動服務
消息處理:
/*** 消息處理* @author yinjihuan**/public class ServerStringHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {System.err.println("server:" + msg.toString());ctx.writeAndFlush(msg.toString() + "你好");}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}}
啟動服務,指定端口為2222:
public static void main(String[] args) {int port = 2222;new Thread(() -> {new ImServer().run(port);}).start();}
編寫客戶端連接邏輯:
public class ImConnection {private Channel channel;public Channel connect(String host, int port) {doConnect(host, port);return this.channel;}private void doConnect(String host, int port) {EventLoopGroup workerGroup = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(workerGroup);b.channel(NioSocketChannel.class);b.option(ChannelOption.SO_KEEPALIVE, true);b.handler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast("decoder", new StringDecoder());ch.pipeline().addLast("encoder", new StringEncoder());ch.pipeline().addLast(new ClientStringHandler());}});ChannelFuture f = b.connect(host, port).sync();channel = f.channel();} catch(Exception e) {e.printStackTrace();}}}
客戶端消息處理:
/*** 當編解碼器為字符串時用來接收數據* @author yinjihuan**/public class ClientStringHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {System.out.println("client:" + msg.toString());}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}}
客戶端啟動入口,然后發送消息給服務端:
public static void main(String[] args) {String host = "127.0.0.1";int port = 2222;Channel channel = new ImConnection().connect(host, port);channel.writeAndFlush("yinjihuan");}
測試步驟如下:
- 首先啟動服務端
- 啟動客戶端,發送消息
- 服務端收到消息,控制台有輸出
server:yinjihuan - 客戶端收到服務端回復的消息,控制台有輸出
client:yinjihuan你好
源碼參考:https://github.com/yinjihuan/netty-im
更多技術分享請關注微信公眾號:猿天地
