本章主要学习内容如下:
1、WebSocket入门

2、Netty WebSocket协议开发

第节一:WebSocket入门

WebSocket是HTML5开始提供的一种浏览器与服务器进行全双通信的网络技术,WebSocket通信协议与2011年被IEIF定位标准RFC6455,WebsSocket api被W3c定为标准。

在WebSocket api中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间形成了一条快速通道,两者就可以之间互相传输消息数据了。WebSocket基于TCP双向全双工进行消息传递,同一时刻,既可以发送消息,也可以接受消息,相比HTTP的半双工协议,性能得到很大的提升。

下面总结一下WebSocket的特点

1、单一TCP连接,采用全双工模式通信。

2、对代理、防火墙和路由器透明。

3、无头部信息、Cookie和身份验证

4、无安全开销

5、通过ping/pong 帧保持链路激活状态

6、服务器可以主动传递消息给客户端,不需要客户端轮训。

WebSocket背景

WebSocket设计出来的目的就是取代轮训和Comet技术,使客户端浏览器具备向C/S架构下桌面系统一样的实时通讯能力。浏览器通过javascript 向服务器发出建立WebSocket连接的请求,连接成功后,客户端和服务端可以通过TCP直接交互数据。因为WebSocket连接本质上就是一个TCP连接,所以在数据传输的稳定性和数据传输量的大小方面,和轮训即Comet技术相比,具有很大的优势。WebSocket.org网站对传统的轮训方式和WebSocket 调用方式作了一个详细的测试和比较,将一个简单的web应用分别通过轮训方式和websocket方式来实现,在这里引用一下测试结果,如图所示:

WebSocket 连接建立

客户端和服务端建立连接的示意图如下:

建立WebSocket连接时,需要通过客户端或者浏览器发出握手请求,请求消息如图所示:

为了建立一个WebSocket 连接,客户端浏览器首先向服务器发起一个HTTP请求,这个请求和通常的HTTP请求不同,包含了一些附加头信息,其中附加头信息“Upgrade:Websocket”表明这是一个申请协议升级的HTTP请求。服务端解析这些附加头信息,然后生成应答信息返回客户端,客户端和服务端的WebSoket连接就建立起来了,双方可以通过这个连接通道自由传递信息,并且这个连接会持续存在直到客户端或服务器端的某一方主动关闭连接。

请求消息中的"sec-websocket-key"是随机的,服务器会用这些数据构造出一个SHA-1的消息摘要,把“sec-websocket-key”加上一个魔幻字符串“*************”。使用SHA-1加密,然后进行Base64编码,将结果作为"sec-websocket-accept"头的值,返回给客户端。
WebSocket 生命周期

第三节:Netty WebSocket协议开发

Websocket服务端的功能如下:支持websocket的浏览器通过websocket协议发送请求消息给客户端,服务端对请求消息进行判断,如果是合法的websocket 请求,则获取请求消息文本,并在后面追加字符串“欢迎使用Netty websocket 服务”。

客户端HTML通过内嵌的js 脚本创建websocke 连接,如果握手成功,在文本框中打印“打开websocket 服务正常,浏览器支持websocket ”。客户端界面如图所示:

WebSocketServer.java

package com.viagra.chapter11.websocket;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
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.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler;/*** @Auther: viagra* @Date: 2019/8/2 13:59* @Description:*/
public class WebSocketServer {public void run(int port) throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch)throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast("http-codec",new HttpServerCodec());pipeline.addLast("aggregator",new HttpObjectAggregator(65536));ch.pipeline().addLast("http-chunked",new ChunkedWriteHandler());pipeline.addLast("handler",new WebSocketServerHandler());}});Channel ch = b.bind(port).sync().channel();System.out.println("Web socket server started at port " + port+ '.');System.out.println("Open your browser and navigate to http://localhost:"+ port + '/');ch.closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}public static void main(String[] args) throws Exception {int port = 17888;new WebSocketServer().run(port);}
}

WebSocketServerHandler.java

package com.viagra.chapter11.websocket;import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
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.util.CharsetUtil;import java.util.logging.Level;
import java.util.logging.Logger;
/*** @Auther: viagra* @Date: 2019/8/2 14:02* @Description:*/
public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {private WebSocketServerHandshaker handshaker;@Overrideprotected void messageReceived(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {// WebSocket接入if (o instanceof WebSocketFrame) {System.out.println("request meesage body:"+o);handleWebSocketFrame(channelHandlerContext, (WebSocketFrame) o);}else if(o instanceof FullHttpRequest){System.out.println("server receiver message is:"+o);handleHttpRequest(channelHandlerContext, (FullHttpRequest) o);}}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {ctx.flush();}private void handleHttpRequest(ChannelHandlerContext ctx,FullHttpRequest req) throws Exception {// 构造握手响应返回,本机测试WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws://localhost:17888/websocket", null, false);handshaker = wsFactory.newHandshaker(req);if (handshaker == null) {WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());} else {handshaker.handshake(ctx.channel(), req);}}private void handleWebSocketFrame(ChannelHandlerContext ctx,WebSocketFrame frame) {// 判断是否是关闭链路的指令if (frame instanceof CloseWebSocketFrame) {handshaker.close(ctx.channel(),(CloseWebSocketFrame) frame.retain());return;}// 判断是否是Ping消息if (frame instanceof PingWebSocketFrame) {ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));return;}// 本例程仅支持文本消息,不支持二进制消息if (!(frame instanceof TextWebSocketFrame)) {throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass().getName()));}// 返回应答消息String request = ((TextWebSocketFrame) frame).text();System.out.println("server receiver message is:"+request);ctx.channel().write(new TextWebSocketFrame(request+ " , welocme to:"+ new java.util.Date().toString()));}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}
}

client.html

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8">Netty WebSocket 时间服务器
</head>
<br>
<body>
<br>
<script type="text/javascript">var socket;if (!window.WebSocket){window.WebSocket = window.MozWebSocket;}if (window.WebSocket) {socket = new WebSocket("ws://localhost:17888/websocket");socket.onmessage = function(event) {var ta = document.getElementById('responseText');ta.value="";ta.value = event.data};socket.onopen = function(event) {var ta = document.getElementById('responseText');ta.value = "打开WebSocket服务正常,浏览器支持WebSocket!";};socket.onclose = function(event) {var ta = document.getElementById('responseText');ta.value = "";ta.value = "WebSocket 关闭!";};}else{alert("抱歉,您的浏览器不支持WebSocket协议!");}function send(message) {if (!window.WebSocket) { return; }if (socket.readyState == WebSocket.OPEN) {socket.send(message);}else{alert("WebSocket连接没有建立成功!");}}
</script>
<form οnsubmit="return false;"><input type="text" name="message" value="Netty最佳实践"/><br><br><input type="button" value="发送WebSocket请求消息" οnclick="send(this.form.message.value)"/><hr color="blue"/><h3>服务端返回的应答消息</h3><textarea id="responseText" style="width:500px;height:300px;"></textarea>
</form>
</body>
</html>

执行结果服务端:

客户端:

netty 权威指南~第11章——WebSoket协议开发相关推荐

  1. JavaScript权威指南 第11章JavaScript标准库

    JavaScript权威指南 第11章JavaScript标准库 第11章 JavaScript标准库 11.1 集合与映射 11.1.1 Set类 11.1.2 Map类 11.1.3 WeakMa ...

  2. Squid中文权威指南-第11章 重定向器

    重定向器是squid的外部程序,它重写来自客户请求的URI.例如,尽管某个用户请求这个页面:http://www.example.com/page1.html ,重定向器可以将请求改变到别的地方,例如 ...

  3. 《Netty权威指南》

    <Netty权威指南> 基本信息 作者: 李林锋 出版社:电子工业出版社 ISBN:9787121233432 上架时间:2014-5-29 出版日期:2014 年6月 开本:16开 页码 ...

  4. [201504][Netty 权威指南][第2版][李林锋][著]

    [201504][Netty 权威指南][第2版][李林锋][著] https://github.com/wuyinxian124/nettybook2 基础篇 走进 Java NIO 第 1 章 J ...

  5. netty权威指南目录

    目录 第一版 第二版 第一版 目录 基础篇 走进Java NIO 第1章 Java的I/O演进之路 1.1 I/O基础入门 1.1.1 Linux网络I/O模型简介 1.1.2 I/O多路复用技术 1 ...

  6. 《Netty权威指南》笔记 —— 第二十、二十一、二十二, 二十三章

    <Netty权威指南>笔记--Netty高级特性 第20章 Netty架构剖析 Reactor通信调度层 职责链 ChannelPipeline 业务逻辑编排层 关键架构质量属性 高性能 ...

  7. netty权威指南第一章

    本章内容如下: 5种网络I/O模型的介绍 I/O多路复用的介绍 1.I/O基础入门 在Java1.4之前,Java对I/O的支持不完善,开发人员在开发高性能I/O的程序时,会面临以下问题: 没有数据缓 ...

  8. Netty权威指南(四)TCP粘包/拆包问题

    TCP粘包/拆包问题解决之道 上一章 一.介绍 1.1 TCP粘包/拆包问题说明 1.2 TCP粘包/拆包发生的原因 1.3 粘包问题的解决策略 二.未考虑TCP粘包导致的功能异常案例 2.1 Tim ...

  9. netty权威指南笔记-以回车换行结尾的消息如何处理半包问题

    概述 TCP底层会发生粘包和拆包,这个是TCP的一个特性.为了减少网络数据传输的次数,TCP总是希望让网络数据到达一定量级的时候才将数据发送出去,而不是缓存区一有数据就马上发送数据. TCP底层会根据 ...

  10. IT人物之《Netty权威指南》中文作者 专访华为李林锋:我与Netty那些不得不说的事

    摘要:Netty是业界最流行的NIO框架之一,它的健壮性.功能.性能.可定制性和可扩展性在同类框架中都是首屈一指的.近日,CSDN采访了Netty领域的权威人士李林锋,请他分享Netty开发的经验之道 ...

最新文章

  1. appium: adb server is out of date.killing
  2. 计算机科目三教学设计,信息技术-教学设计模板(科目三).pdf
  3. linux线程一直在增加,在.net core中遇到的奇怪问题:内存与线程数一直增长
  4. 如何在WhatsApp中将群聊静音
  5. 克隆后 mysql uuid_mysql主从复制失败(uuid)
  6. 欧姆龙nb触摸屏通信_欧姆龙触摸屏 NB系列
  7. 常用的计算机网络设备有,常用网络设备有哪些,初学者必须要知道的五大网络设备...
  8. cygwin解压linux软件,如何在Cygwin上安装unzip | 望天博客
  9. An工具介绍之3D工具
  10. 德州停电悲剧不会重演 智慧用电是新方向
  11. 用妙记多 Mojidoc 实践康奈尔笔记法
  12. 你的微信接收消息也会延迟吗?原因居然出在这,一招教你轻松解决
  13. [渝粤题库]西北工业大学电工与电子技术
  14. js中利用prompt和parseFloat来实现用户体温华氏和摄氏的提取(18)
  15. 基于ISOMAP算法实现测地线的绘制
  16. Nginx启动报错:error while loading shared libraries: libpcre.so.1
  17. 蓝色经典钢琴-Cinesamples Piano In Blue v2.3b Kontakt
  18. 分享一个开源的QT的串口示波器
  19. 剑指offer-字符串总结
  20. 分页计算起始页和总页数

热门文章

  1. iOS悬浮、可拖动、自动吸附屏幕边缘的按钮制作
  2. 最新 CCF A 类人工智能会议论文下载汇总 (含2022)
  3. 百度搜索无法显示搜索结果
  4. 大学生咖啡网页制作教程 表格布局网页模板 学生HTML静态美食网页设计作业成品 简单网页制作代码 学生美食网页作品免费设计
  5. Linux指令篇:文件系统--fdisk(转)
  6. D/E盘根目录出现Msdia80.dll操作;dllregisterserver调用失败错误代码0x80004005 解决
  7. linux 之间复制文件,两台Linux服务器之间复制文件
  8. 《那些年啊,那些事——一个程序员的奋斗史》——18
  9. 在线小说网站的设计与实现(附源码)
  10. ygbook小说网站源码 自动采集赚钱源码 ThinkPHP+MYSQL开发