我是靠谱客的博主 无情绿草,这篇文章主要介绍Netty学习——基于Netty的WebSocket协议开发     基于Netty的WebSocket协议开发,现在分享给大家,希望可以做个参考。

     基于Netty的WebSocket协议开发

WebSocket简介

        Java的Socket是Java网络编程的基础,Java的Socket是在应用层的,这和C/C++的Socket不同,C/C++的Socket是可以获取TCP头数据的。Socket是一种全双工的通信方式,也就是说通信双方可以同时互发消息,也叫CS模式,而HTTP协议是一种无状态协议,是基于BS模式的,服务器不能主动给客户端发消息,只能由客户端发起请求,服务器给予响应。HTTP的这种BS模式在HTTP的Web1.0和Web2.0还是很好用的,但是现在用户交互越来越丰富,很多时候也需要服务器能够主动给客户端发送消息数据,以此来增加用户体验度,或者是实现实时网络通信的效果。然而由于HTTP的特性,这在以前是个很大的技术难题。有一些产品基于轮询和长连接做出了一些解决方案,比如说gmail的在线聊天。但由于长连接轮询都比较耗资源,不能像Socket那样灵活,因而基于HTTP的这些解决方案都没能得到较好的认可。
      HTML5开始为为浏览器与服务器通信提供WebSocket解决方案并提供了相应的API,WebSocket与Socket非常相似,并且Web Socket和Socket的API风格也非常的相似。在使用WebSocket时,只需要像Socket那样服务器端和客户端进行一次握手操作,就可以生成一个服务器端-客户端数据传输的双向通道,客户端向服务器发送数据的同时服务器也可以向客户端发送数据,因此,WebSocket也是全双工的网络通信模式。WebSocket之所以比HTTP的长连接轮询更优秀,更重要的原因是它和Socket一样对代理、防火墙路由器透明,而且每次的数据传输没有携头部信息以为Cookie之类的额外数据,这样就可以尽量减少网络流量,提高网络通信的效率。
      WebSocket建立连接时,首先客户端会向服务器端发送一个HTTP请求,这个请求包含了一些额外的头部信息,比如"Upgrade:WebSocket"表示这个请求要创建一个WebSocket连接。

用Netty实现WebSocket

      Netty已经实现了WebSocket的细节,我们在使用时只需要创建一个WebSocket的握手对象即可,在接收消息时,要判断消息是普通Http消息还是WebSocket的消息,如果是普通的消息,则通过获取请求头中的Upgrade中的数据,如果是"websocket"的话,就表示这个Http消息是用来创建WebSocket连接的,这时候,就可以创建一个Websocket握手对象。如果消息对象是一个WebSocket消息,就取出其中的内容,进行相应的逻辑处理,最后再写回一个WebScoket消息即完成了一次客户端向服务器请求WebSocket网络通信过程,当然我们也可以主动给客户端发送消息,我们在handler active之后就每秒钟来查询是否已经创建了WebSocket握手对象,如果已经创建了,就向客户端写一条消息,这就是服务器主动给客户端发送消息,实现网络双工通信,下面是实现这个例子的Java代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package study.netty; import java.util.TimerTask; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.util.Timer; public class NettyWebSocketServer { public static void main(String[] args) { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup,workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast("http-codec",new HttpServerCodec()) .addLast("aggregator",new HttpObjectAggregator(65535)) .addLast("http-chunked",new ChunkedWriteHandler()) .addLast("handler",new WebSocketServerHandler()); } }); try { bootstrap.bind(8080).sync().channel().closeFuture().sync(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } private static class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>{ private WebSocketServerHandshaker handshaker; @Override protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof FullHttpRequest) {//建立连接的请求 handleHttpRequest(ctx,(FullHttpRequest)msg); }else if (msg instanceof WebSocketFrame){//WebSocket handleWebsocketFrame(ctx,(WebSocketFrame)msg); } } private void handleWebsocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { if (frame instanceof CloseWebSocketFrame) {//关闭 handshaker.close(ctx.channel(), (CloseWebSocketFrame)frame.retain()); }else if (frame instanceof PingWebSocketFrame) {//ping消息 ctx.channel().write(new PongWebSocketFrame(frame.content().retain())); }else if (frame instanceof TextWebSocketFrame) {//文本消息 String request = ((TextWebSocketFrame)frame).text(); ctx.channel().write(new TextWebSocketFrame("websocket return:"+request)); } } private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request) { if(request.getDecoderResult().isSuccess()&&"websocket".equals(request.headers().get("Upgrade"))) { System.out.println("create WebSocket connection"); WebSocketServerHandshakerFactory factory = new WebSocketServerHandshakerFactory("ws://localhost:8080/websocket", null, false); handshaker = factory.newHandshaker(request);//通过创建请求生成一个握手对象 if(handshaker != null) { handshaker.handshake(ctx.channel(),request); } } } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { new java.util.Timer().schedule(new TimerTask() { @Override public void run() { if(handshaker !=null) { ctx.channel().write(new TextWebSocketFrame("server:主动给客户端发消息")); ctx.flush(); } } }, 1000,1000); } } }

下面是客户端的代码,客户端是一个网页,上面的输入框用来输入消息发送给服务器,下面的文本域是用来显示历史消息的。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<html> <head> <title>test</title> </head> <body> <form οnsubmit="return false;"> <input type="text" name="message"> <button οnclick="send(this.form.message.value)">send</button> <br> <h3>return messages</h3> <textarea id="returns" rows="10" cols="30"></textarea> </form> </body> <script type="text/javascript"> var socket if(!window.WebSocket){ window.WebSocket = window.MozWebSocket } if(window.WebSocket){ socket = new WebSocket("ws://localhost:8080/websocket") socket.onmessage = function(event){ var returns = document.getElementById("returns") returns.value = returns.value + "n" returns.value = returns.value + event.data } socket.onopen = function(event){ var returns = document.getElementById("returns") returns.value = returns.value + "n" returns.value = returns.value + "已经连接上WebSocket服务器" } socket.onclose = function(event){ var returns = document.getElementById("returns") returns.value = returns.value + "n" returns.value = returns.value + "断开与Socket服务器的连接" } } function send(msg){ if(!socket){ alert() return } if(socket.readyState == WebSocket.OPEN){ socket.send(msg) }else{ alert("WebSocket还未连接成功") } } </script> </html>
 运行Java程序,然后打开网页,就会显示已经连接上WebSocket服务器,并且每过一秒就会自动接收到服务器发来的消息,如果
输入数据的话,服务器会把数据返回并在前面加上一个"return:"


最后

以上就是无情绿草最近收集整理的关于Netty学习——基于Netty的WebSocket协议开发     基于Netty的WebSocket协议开发的全部内容,更多相关Netty学习——基于Netty的WebSocket协议开发 内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部