简介在网络速度飞速提升的时代,浏览器已经成为我们访问各种服务的入口。很难想象如果没有浏览器,我们的网络世界将如何运作。现在我迫不及待地想把操作系统搬到浏览器上了。但并不是所有的应用程序都需要浏览器来执行,比如服务器之间的通信,就需要使用自建的客户端与服务器进行交互。本文将介绍使用netty客户端连接websocket的原理和具体实现。浏览器客户端在介绍netty客户端之前,先来看一个简单的浏览器客户端连接websocket的例子://创建一个连接constsocket=newWebSocket('ws://localhost:8000');//打开Connectsocket。addEventListener('open',function(event){socket.send('是的,打开了!');});//监听消息socket.addEventListener('message',function(event){console.log('监听服务器的消息',event.data);});这里使用了浏览器最常用的javascript语言,使用浏览器提供的websocketAPI进行操作,非常简单。那么使用netty客户端实现websocket连接和使用javascript是一样的吗?让我们一起探索。Netty对websocket客户端的支持首先我们来看看netty对websocket的支持有哪些,然后再详细看看这些工具的使用方法。WebSocketClientHandshaker和websocketserver一样,client中的核心类也是handshaker,这里称之为WebSocketClientHandshaker。这个类的作用是什么?让我们来看看。该类主要实现客户端与服务端的握手。我们看一下它最长参数的构造类:protectedWebSocketClientHandshaker(URIuri,WebSocketVersionversion,Stringsubprotocol,HttpHeaderscustomHeaders,intmaxFramePayloadLength,longforceCloseTimeoutMillis,booleanabsoluteUpgradeUrl)参数中包含websocket连接的URI,如:“ws//flydean.com/mypath”。有请求子协议的类型子协议,有自定义HTTP头:customHeaders,有最大帧负载长度:maxFramePayloadLength,有强制超时关闭时间,有使用HTTP协议升级的URI地址.如何创建握手器?同样,netty提供了一个WebSocketClientHandshakerFactory方法。WebSocketClientHandshakerFactory提供了一个newHandshaker方法,可以方便的创建不同版本的handshaker:==V08){returnnewWebSocketClientHandshaker08(webSocketURL,V08,subprotocol,allowExtensions,customHeaders,maxFramePayloadLength,performMasking,allowMaskMismatch,forceCloseTimeoutMillis);}if(version==V07){returnnewWebSocketClientHandshaker07(webSocketURL,V07,subprotocol,allowExtensions,customHeaders,maxFramePayloadLength,performMasking,allowMaskMismatch,forceCloseTimeoutMillis);}if(version==V00){返回新的WebSocketClientHandshaker00(webSocketURL、V00、子协议、customHeaders、maxFramePayloadLength、forceCloseTimeoutMillis);}可以看到,根据传入协议版本的不同,可以分为WebSocketClientHandshaker13、WebSocketClientHandshaker08、WebSocketClientHandshaker07、WebSocketClientHandshaker00这几种WebSocketClientCompressionHandler通信常说的,针对webSocket的传输性能和降低带宽使用率,针对webSocket协,通常在使用过程中添加额外的压缩和扩展。为了处理这样的压缩和扩展,netty提供了服务器端和客户端的支持。服务器对应的处理程序称为WebSocketServerCompressionHandler,客户端对应的处理程序称为WebSocketClientCompressionHandler。通过将这两个handler添加到对应的pipeline中,可以实现对websocket中压缩协议扩展的支持。协议扩展有两个级别:permessage-deflate和perframe-deflate,分别对应PerMessageDeflateClientExtensionHandshaker和DeflateFrameClientExtensionHandshaker。至于如何压缩,这里就不详细解释了,有兴趣的朋友可以自行了解。netty客户端的处理流程在讲解完netty对websocket客户端的支持之后,本节将讲解netty是如何使用这些工具进行消息处理的。首先是根据正常逻辑创建客户端Bootstrap并添加处理程序。这里的handler是专门为websocket定制的client-sidehandler。除了上面提到的WebSocketClientCompressionHandler之外,它是一个自定义的处理程序。在自定义处理程序中,我们需要处理两件事,一件事是在通道准备好时创建一个握手器。另一件事是具体的websocket消息的处理。要创建一个握手器,首先使用WebSocketClientHandshakerFactory创建一个处理程序:然后在通道握手处于活动状态时使用它:然后在接收和处理消息时,需要判断握手状态是否完成。如果没有,调用handshaker.finishHandshake方法手动完成:if(!handshaker.isHandshakeComplete()){log.info("websocket握手完成!");handshakeFuture.setSuccess();}catch(WebSocketHandshakeExceptione){log.info("websocket连接失败!");handshakeFuture.setFailure(e);}返回;}当握手完成后,就可以进行正常的websocket消息读写操作了。Websocket消息处理Websocket消息处理比较简单,只需将接收到的消息转换成WebSocketFrame进行处理即可。WebSocketFrame框架=(WebSocketFrame)消息;if(frameinstanceofTextWebSocketFrame){TextWebSocketFrametextFrame=(TextWebSocketFrame)frame;log.info("收到TXT消息:"+textFrame.text());}elseif(frameinstanceofPongWebSocketFrame){log.info("pongmessagereceived");}elseif(frameinstanceofCloseWebSocketFrame){log.info("closingmessagereceived");ch.close();}小结本文讲解了netty提供的websocket客户端端到端的支持和具体的对接流程,大家可以在基础上再次扩展,实现自己的业务逻辑。本文示例可参考:learn-netty4本文已收录于http://www.flydean.com/25-netty-websocket-client/最流行的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等你来发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!
