netty發送和接收數據handler處理器 主要是繼承 SimpleChannelInboundHandler 和 ChannelInboundHandlerAdapterweb
通常用netty來發送和接收數據都會繼承SimpleChannelInboundHandler和ChannelInboundHandlerAdapter這兩個抽象類,那麼這兩個到底有什麼區別呢?服務器
其實用這兩個抽象類是有講究的,在客戶端的業務Handler繼承的是SimpleChannelInboundHandler,而在服務器端繼承的是ChannelInboundHandlerAdapter。session
最主要的區別就是SimpleChannelInboundHandler在接收到數據後會自動release掉數據佔用的Bytebuffer資源(自動調用Bytebuffer.release())。而爲什麼服務器端不能用呢,由於咱們想讓服務器把客戶端請求的數據發送回去,而服務器端有可能在channelRead方法返回前尚未寫完數據,所以不能讓它自動release。ide
handler處理器 內置 方法this
通道激活時觸發,當客戶端connect成功後,服務端就會接收到這個事件,從而能夠把客戶端的Channel記錄下來,供後面複用spa
這個必須用啊,當收到對方發來的數據後,就會觸發,參數msg就是發來的信息,能夠是基礎類型,也能夠是序列化的複雜對象。netty
channelRead執行後觸發code
出錯是會觸發,作一些錯誤處理orm
繼承 ChannelInboundHandlerAdapter 具體的例子對象
/** * netty服務器的監聽 處理器 * * @author flm 2017年10月27日 */ public class IOHandler extends ChannelInboundHandlerAdapter { private static Logger log = Logger.getLogger(IOHandler.class); //netty AttributeKey 相對於 web session【重要】 public static final AttributeKey<DeviceSession> KEY = AttributeKey.valueOf("IO"); private Producer producer; public IOHandler(Producer producer){ this.producer=producer; } /** * 讀取數據 */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { DeviceSession session = ctx.channel().attr(KEY).get(); // 檢測是否 本身註冊的 客戶端 ByteBuf buffer=(ByteBuf) msg; if (buffer == null||session == null) { closeConnection(ctx); // 關閉鏈接 } MsgEntity msgEntity = new MsgEntity(buffer); // 解碼 buffer 封裝 msgEntity log.info("# Accept Client data :"+msgEntity.toString()); if (MsgType.UNKNOW == msgEntity.getMsgType()) { log.info("# 客戶端 發送數據 類型未定義... :"+msgEntity.toString()); return; } if(!session.isActivity()){ session.setActivity(true); session.setImei(msgEntity.getImei()); SessionManager.getSingleton().addClient(session); } producer.putData(msgEntity); } /** * 客戶端 註冊 */ @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { super.channelRegistered(ctx); log.info(String.format("# client registered...: %s ...", ctx.channel())); DeviceSession session = new DeviceSession(ctx.channel()); // 綁定客戶端到SOCKET ctx.channel().attr(KEY).set(session); } /** * 客戶端 失去鏈接 */ @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { super.channelInactive(ctx); log.info(String.format("# client out... : %s", ctx.channel())); DeviceSession session = ctx.channel().attr(KEY).getAndSet(null); // 移除 session 並刪除 該客戶端 SessionManager.getSingleton().removeClient(session, true); if(session.getDeviceID() != null) { // producer.onData(new Request(new RootMessage(MessageType.LOGOUT, null, null), session)); } } /** * 心跳機制 用戶事件觸發 */ @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof IdleStateEvent) { IdleStateEvent e = (IdleStateEvent) evt; //檢測 是否 這段時間沒有和服務器聯繫 if (e.state() == IdleState.ALL_IDLE) { //檢測心跳 checkIdle(ctx); } } super.userEventTriggered(ctx, evt); } /** * 報錯 處理事件 */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { log.error("# 客戶端鏈接 Netty 出錯..."); cause.printStackTrace(); //關閉鏈接 closeConnection(ctx); }