轉https://blog.csdn.net/alwaysRise/article/details/121002198
netty+websocket下pipeline中handler無法傳遞的問題
在ChannelPipeline中責任鏈的傳遞
點擊查看代碼
ChannelPipeline pipeline = socketChannel.pipeline();
//websocket協議本身是基於http協議的,所以這邊也要使用http解編碼器
pipeline.addLast(new HttpServerCodec());
//以塊的方式來寫的處理器
pipeline.addLast(new ChunkedWriteHandler());
//netty是基於分段請求的,HttpObjectAggregator的作用是將請求分段再聚合,參數是聚合字節的最大長度
pipeline.addLast(new HttpObjectAggregator(8192));
// pipeline.addLast(new ReadTimeoutHandler(60));
pipeline.addLast(httpRequestHandler);
//ws://server:port/context_path
//ws://localhost:9999/ws
//參數指的是contex_path
pipeline.addLast(new WebSocketServerProtocolHandler("/xdong",true));
//websocket定義了傳遞數據的6中frame類型
pipeline.addLast(xdongTextWebSocketFrameHandler);
在責任鏈中有兩個我自定義的handler,分別是httpRequestHandler和xdongTextWebSocketFrameHandler,這兩個handler的作用分別是處理http請求下的token身份驗證和完成握手升級以及處理握手完成之后接收ws客戶端傳入的消息。
但是在我的代碼過程中發生了問題,客戶端能成功和服務器建立通道,但是卻無法完成后續的消息傳輸,網上在線的ws測試客戶端和我的服務端建立連接的時候也提示未收到服務端的握手包。
經過大佬的排查發現我在我的handler中並沒有通過fire時間將消息給責任鏈中的下一個handler處理,實際上我雖然建立了通道但是卻沒有完成握手,更無法處理消息。
其中三個重要的handler在責任鏈中的順序是這樣的:
點擊查看代碼
pipeline.addLast(httpRequestHandler);
//ws://server:port/context_path
//ws://localhost:9999/ws
//參數指的是contex_path
pipeline.addLast(new WebSocketServerProtocolHandler("/xdong",true));
//websocket定義了傳遞數據的6中frame類型
pipeline.addLast(xdongTextWebSocketFrameHandler);
httpRequestHandler這個handler放第一個的原因是第一次握手的時候,請求實際上還是個http請求, 我可以拿到url中的token完成身份驗證的工作。但是完成了之后還需要調用下一個handler完成http到ws協議的升級。
WebSocketServerProtocolHandler這個handler是io.netty包中自帶的handler用來完成http協議到websocket協議的升級, 並且明確提到消息處理的handler必須在該handler之后。
xdongTextWebSocketFrameHandler是一個消息處理的handler,在成功建立ws連接后用來接收客戶端傳輸的消息。
在pipeLine中的加入順序都是addLast, 所以都是有順序的。在channelRead0方法中處理完當前的邏輯之后需要通過fire事件觸發下一個InboundHandler。方法就是ctx.fireChannelRead(((FullHttpRequest) msg).retain())
@Override protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof FullHttpRequest) { handleHttpRequest(ctx, (FullHttpRequest) msg); ctx.fireChannelRead(((FullHttpRequest) msg).retain()); } else if (msg instanceof WebSocketFrame) { ctx.fireChannelRead(((WebSocketFrame) msg).retain()); } }