netty搭建Tcp伺服器實踐
在中,我們大致瞭解了netty的一些基本元件,今天我們來搭建一個基於netty的Tcp服務端程式,透過程式碼來了解和熟悉這些元件的功能和使用方法。
首先我們自己建立一個Server類,命名為TCPServer
第一步初始化ServerBootstrap,ServerBootstrap是netty中的一個伺服器引導類,對ServerBootstrap的例項化就是建立netty伺服器的入口
public class TCPServer { private Logger log = LoggerFactory.getLogger(getClass()); //埠號 private int port=5080; //伺服器執行狀態 private volatile boolean isRunning = false; //處理Accept連線事件的執行緒,這裡執行緒數設定為1即可,netty處理連結事件預設為單執行緒,過度設定反而浪費cpu資源 private final EventLoopGroup bossGroup = new NioEventLoopGroup(1); //處理hadnler的工作執行緒,其實也就是處理IO讀寫 。執行緒資料預設為 CPU 核心數乘以2 private final EventLoopGroup workerGroup = new NioEventLoopGroup(); public void init() throws Exception{ //建立ServerBootstrap例項 ServerBootstrap serverBootstrap=new ServerBootstrap(); //初始化ServerBootstrap的執行緒模型 serverBootstrap.group(workerGroup,workerGroup);// //設定將要被例項化的ServerChannel類 serverBootstrap.channel(NioServerSocketChannel.class);// //在ServerChannelInitializer中初始化ChannelPipeline責任鏈,並新增到serverBootstrap中 serverBootstrap.childHandler(new ServerChannelInitializer()); //標識當伺服器請求處理執行緒全滿時,用於臨時存放已完成三次握手的請求的佇列的最大長度 serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024); // 是否啟用心跳保活機機制 serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true); //繫結埠後,開啟監聽 ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); if(channelFuture.isSuccess()){ System.out.println("TCP服務啟動 成功---------------"); } } /** * 服務啟動 */ public synchronized void startServer() { try { this.init(); }catch(Exception ex) { } } /** * 服務關閉 */ public synchronized void stopServer() { if (!this.isRunning) { throw new IllegalStateException(this.getName() + " 未啟動 ."); } this.isRunning = false; try { Future<?> future = this.workerGroup.shutdownGracefully().await(); if (!future.isSuccess()) { log.error("workerGroup 無法正常停止:{}", future.cause()); } future = this.bossGroup.shutdownGracefully().await(); if (!future.isSuccess()) { log.error("bossGroup 無法正常停止:{}", future.cause()); } } catch (InterruptedException e) { e.printStackTrace(); } this.log.info("TCP服務已經停止..."); } private String getName() { return "TCP-Server"; } }
上面的程式碼中主要使用到的ServerBootstrap類的方法有以下這些:
group :設定SeverBootstrap要用到的EventLoopGroup,也就是定義netty服務的執行緒模型,處理Acceptor連結的主"執行緒池"以及用於I/O工作的從"執行緒池";
channel:設定將要被例項化的SeverChannel類;
option :指定要應用到新建立SeverChannel的ChannelConfig的ChannelOption.其實也就是服務本身的一些配置;
chidOption:子channel的ChannelConfig的ChannelOption。也就是與客戶端建立的連線的一些配置;
childHandler:設定將被新增到已被接收的子Channel的ChannelPipeline中的ChannelHandler,其實就是讓你在裡面定義處理連線收發資料,需要哪些ChannelHandler按什麼順序去處理;
第二步接下來我們實現ServerChannelInitializer類,這個類繼承實現自netty的ChannelInitializer抽象類,這個類的作用就是對channel(連線)的ChannelPipeline進行初始化工作,說白了就是你要把處理資料的方法新增到這個任務鏈中去,netty才知道每一步拿著socket連線和資料去做什麼。
@ChannelHandler.Sharablepublic class ServerChannelInitializer extends ChannelInitializer<SocketChannel> { static final EventExecutorGroup group = new DefaultEventExecutorGroup(2); public ServerChannelInitializer() throws InterruptedException { } @Override protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline pipeline = socketChannel.pipeline(); //IdleStateHandler心跳機制,如果超時觸發Handle中userEventTrigger()方法 pipeline.addLast("idleStateHandler", new IdleStateHandler(15, 0, 0, TimeUnit.MINUTES)); // netty基於分割符的自帶解碼器,根據提供的分隔符解析報文,這裡是0x7e;1024表示單條訊息的最大長度,解碼器在查詢分隔符的時候,達到該長度還沒找到的話會拋異常// pipeline.addLast(// new DelimiterBasedFrameDecoder(1024, Unpooled.copiedBuffer(new byte[] { 0x7e }),// Unpooled.copiedBuffer(new byte[] { 0x7e }))); //自定義編解碼器 pipeline.addLast( new MessagePacketDecoder(), new MessagePacketEncoder() ); //自定義Hadler pipeline.addLast("handler",new TCPServerHandler()); //自定義Hander,可用於處理耗時操作,不阻塞IO處理執行緒 pipeline.addLast(group,"BussinessHandler",new BussinessHandler()); } }
這裡我們注意下
pipeline.addLast(group,"BussinessHandler",new BussinessHandler());
在這裡我們可以把一些比較耗時的操作(如儲存、入庫)等操作放在BussinessHandler中進行,因為我們為它單獨分配了EventExecutorGroup 執行緒池執行,所以說即使這裡發生阻塞,也不會影響TCPServerHandler中資料的接收。
最後就是各個部分的具體實現
解碼器的實現:
public class MessagePacketDecoder extends ByteToMessageDecoder { public MessagePacketDecoder() throws Exception { } @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception { try { if (buffer.readableBytes() > 0) { // 待處理的訊息包 byte[] bytesReady = new byte[buffer.readableBytes()]; buffer.readBytes(bytesReady); //這之間可以進行報文的解析處理 out.add(bytesReady ); } }finally { } } }
編碼器的實現
public class MessagePacketEncoder extends MessageToByteEncoder<Object>{ public MessagePacketEncoder() { } @Override protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { try { //在這之前可以實現編碼工作。 out.writeBytes((byte[])msg); }finally { } } }
TCPServerHandler的實現
public class TCPServerHandler extends ChannelInboundHandlerAdapter { public TCPServerHandler() { } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //拿到傳過來的msg資料,開始處理 } //檢測到空閒連線,觸發 @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { //這裡可做一些斷開連線的處理 } }
BussinessHandler的實現與TCPServerHandler基本類似,它可以處理一些相對比較耗時的操作,我們這裡就不實現了。
透過以上的程式碼我們可以看到,一個基於netty的TCP服務的搭建基本就是三大塊:
1、對引導伺服器類ServerBootstrap的初始化;
2、對ChannelPipeline的定義,也就是把多個ChannelHandler組成一條任務鏈;
3、對 ChannelHandler的具體實現,其中可以有編解碼器,可以有對收發資料的業務處理邏輯;
以上程式碼只是在基於netty框架搭建一個最基本的TCP服務,其中包含了一些netty基本的特性和功能,當然這只是netty運用的一個簡單的介紹,如有不正確的地方還望指出與海涵。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2035/viewspace-2815272/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- netty系列之:使用netty搭建websocket伺服器NettyWeb伺服器
- Netty FastThreadLocal 實踐NettyASTthread
- Netty、MINA、Twisted一起學系列01:實現簡單的TCP伺服器NettyTCP伺服器
- 從BIO和NIO到Netty實踐Netty
- netty4+protobuf3最佳實踐Netty
- netty系列之:搭建HTTP上傳檔案伺服器NettyHTTP伺服器
- Vert.x TCP 通訊實踐TCP
- 聊聊TCP Keepalive、Netty和DockerTCPNettyDocker
- Netty基礎招式——ChannelHandler的最佳實踐Netty
- Netty乾貨分享:京東京麥的生產級TCP閘道器技術實踐總結NettyTCP
- Netty 實現HTTP檔案伺服器NettyHTTP伺服器
- netty系列之:搭建自己的下載檔案伺服器Netty伺服器
- 手把手教你在netty中使用TCP協議請求DNS伺服器NettyTCP協議DNS伺服器
- libuv中實現tcp伺服器TCP伺服器
- 華為雲彈性雲伺服器ECS搭建FTP服務實踐伺服器FTP
- netty系列之:使用netty實現支援http2的伺服器NettyHTTP伺服器
- Netty實現Http高效能伺服器NettyHTTP伺服器
- Netty(二) 實現簡單Http伺服器NettyHTTP伺服器
- Docker實踐5:搭建redmineDocker
- 《初識TCP》使用Objective-C搭建本地伺服器與遠端伺服器TCPObject伺服器
- netty系列之:從零到壹,搭建一個SOCKS代理伺服器Netty伺服器
- netty系列之:使用netty搭建websocket客戶端NettyWeb客戶端
- Docker Swarm 叢集搭建實踐DockerSwarm
- TCP KeepAlive機制理解與實踐小結TCP
- 無伺服器最佳實踐伺服器
- python 實現 TCP 伺服器最簡流程PythonTCP伺服器
- c 語言實現 tcp/udp 伺服器功能TCPUDP伺服器
- 關於Netty的一些理解、實踐與陷阱Netty
- Redis叢集環境搭建實踐Redis
- 前端圖床搭建實踐(前端篇)前端圖床
- Vagrant 搭建開發環境實踐開發環境
- TCP併發伺服器的程式設計實現TCP伺服器程式設計
- 虛擬伺服器管理實踐伺服器
- 【大型網站技術實踐】初級篇:藉助Nginx搭建反向代理伺服器網站Nginx伺服器
- 深入學習Netty(5)——Netty是如何解決TCP粘包/拆包問題的?NettyTCP
- 詳說TCP重傳問題的排查思路與實踐TCP
- 開源一個自用的Android IM庫,基於Netty+TCP+Protobuf實現。AndroidNettyTCP
- 簡單實踐搭建 nginx 負載均衡Nginx負載