WebSocket协议开发

1. Http协议弊端

  • 半双工协议:同一时刻,只有一个方向上的数据传送(客户端 --> 服务端 或者 服务端 --> 客户端)
  • 消息冗长繁琐
  • 针对服务器推送的黑客攻击。例如长时间轮询,比较新的技术Comet,使用了Ajax,这种技术会大量消耗服务器带宽和资源

2. WebSocket入门

2.1 特点

  • 单一的TCP连接,采用全双工模式通信
  • 对代理、防火墙和路由器透明
  • 无头部信息、Cookie和身份验证
  • 无安全开销
  • 通过“ping/pong”帧保持链路激活
  • 服务器可以主动传递消息给客户端,不在需要客户端轮询

2.2 请求消息

  • Upgrade:表示将http协议升级到WebSocket协议

  • Sec-WebSocket-Key:随机字符串

2.3 应答消息

  • Sec-WebSocket-Accept: 将WebSocket-Key加上一个魔幻字符串,然后使用SHA-1加密,进行BASE-64编码

2.4 请求关闭

正常情况下,应该由服务器先关闭。异常情况下(一个合理时间周期后没有收到服务器的TCP close),客户端可以发起TCP Close。当服务器被指示关闭时,会立即发起关闭WebSocket TCP close操作;客户端应该等待服务器的TCP Close。WebSocket的握手关闭消息带有一个状态码核可选的关闭愿意,必须按照协议要求发送一个Close控制帧,对端收到后需要主动关闭WebSocket连接。

3. 时间服务器

  • 绑定端口,创建netty服务端
  • http-codec:添加Http请求和响应的编码和解码器
  • aggregator:合并http请求
  • http-chunked:添加大文件传输器
  • handler:自定义处理器
public void bind(int port) {NioEventLoopGroup bossGroup = new NioEventLoopGroup();NioEventLoopGroup workGroup = new NioEventLoopGroup();try {ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup, workGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline()//将请求和应答消息解码或者编码成http消息.addLast("http-codec", new HttpServerCodec()).addLast("aggregator", new HttpObjectAggregator(65536)).addLast("http-chunked", new ChunkedWriteHandler()).addLast("handler", new TimeWebSocketServerHandler());}});Channel channelFuture = serverBootstrap.bind(port).sync().channel();System.out.println("Web Socket Server started at port :" + port + ".");System.out.println("open you browser and navigate to http://localhost:" + port + "/");channelFuture.closeFuture().sync();} catch (InterruptedException e) {bossGroup.shutdownGracefully();workGroup.shutdownGracefully();}}

3.1 自定义处理器

public static class TimeWebSocketServerHandler extends SimpleChannelInboundHandler<Object> {private WebSocketServerHandshaker webSocketServerHandshaker;@Overrideprotected void channelRead0(ChannelHandlerContext ctx, Object msg) {if (msg instanceof FullHttpRequest) {this.handleHttpRequest(ctx, (FullHttpRequest) msg);} else {this.handleWebSocketRequest(ctx, (WebSocketFrame) msg);}} }

handleHttpRequest()

  • 判断http请求有没有解码成功,或者协议中没有 Upgrade = websocket 值
  • websocket握手工厂创建 握手协议,如果不支持返回错误码
  • 握手时,就会把 websocket相关的编解码器动态的添加到管道中,后续使用websocket相关对象可以直接获取
/*** 处理http请求* @param ctx* @param fullHttpRequest*/private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) {//http解码失败,并且协议并不是升级为websocketif (!fullHttpRequest.decoderResult().isSuccess() ||(!"websocket".equals(fullHttpRequest.headers().get("Upgrade")))) {sendHttpResponse(ctx, fullHttpRequest, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.BAD_REQUEST));return;}WebSocketServerHandshakerFactory webSocketServerHandshakerFactory= new WebSocketServerHandshakerFactory("ws://localhost:8080/websocket", null, false);webSocketServerHandshaker = webSocketServerHandshakerFactory.newHandshaker(fullHttpRequest);if (Objects.isNull(webSocketServerHandshaker)) {WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());} else {//创建握手时,就会将websocket的编码解码添加到管道中webSocketServerHandshaker.handshake(ctx.channel(), fullHttpRequest);}}

handleWebSocketRequest()

  • 判断各种类型的WebSocketFrame请求,根据类型操作
private void handleWebSocketRequest(ChannelHandlerContext ctx, WebSocketFrame webSocketFrame) {//判断链路是否是关闭的指令if (webSocketFrame instanceof CloseWebSocketFrame) {webSocketServerHandshaker.close(ctx.channel(), (CloseWebSocketFrame) webSocketFrame.retain());return;}if (webSocketFrame instanceof PingWebSocketFrame) {ctx.channel().write(new PongWebSocketFrame(webSocketFrame.content().retain()));return;}//只支持文本消息,不支持二进制消息if (!(webSocketFrame instanceof TextWebSocketFrame)) {throw new UnsupportedOperationException(String.format("%s frame types not supported", webSocketFrame.getClass().getName()));}//返回应答消息String text = ((TextWebSocketFrame) webSocketFrame).text();ctx.channel().writeAndFlush(new TextWebSocketFrame(text + ", 欢迎使用netty websocket服务,现在是北京时间:"+ new Date().toString()));}

sendHttpResponse()

  • 判断状态,写入返回值数据
  • 判断请求是否是长连接,如果不是,添加关闭的监听器
private static void sendHttpResponse(ChannelHandlerContext ctx,FullHttpRequest request,FullHttpResponse response) {if (response.status().code() != 200) {ByteBuf byteBuf = Unpooled.copiedBuffer(response.status().toString(), CharsetUtil.UTF_8);response.content().writeBytes(byteBuf);byteBuf.release();HttpUtil.setContentLength(response, response.content().readableBytes());}ChannelFuture future = ctx.channel().writeAndFlush(response);if (!HttpUtil.isKeepAlive(request) || response.status().code() != 200) {future.addListener(ChannelFutureListener.CLOSE);}}

4. JS页面代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Netty WebSocket 时间服务器</title>
</head>
<body>
<script>var socket;if (!window.WebSocket) {window.WebSocket = window.MozWebSocket;}if (window.WebSocket) {socket = new WebSocket("ws://localhost:8080/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 onsubmit="return false;"><input type="text" name="message" value="Netty 最佳实践"><br><br><input type="button" value="发送 WebSocket请求消息" onclick="send(this.form.message.value)"/><hr color="blue"/><h3>服务端返回应答消息</h3><textarea id="responseText" style="width: 500px;height: 300px"></textarea>
</form>
</body>
</html>

Netty(3)之WebSocket协议开发时间服务器相关推荐

  1. Netty权威指南之Websocket协议开发

    本章主要学习内容如下: 1.HTTP协议弊端 2.WebSocket入门 3.Netty WebSocket协议开发 第一节:HTTP协议弊端 将HTTP协议的主要弊端总结如下: 1.HTTP协议为半 ...

  2. 基于netty实现一个简单的支持http和webSocket协议的的服务器(含xxl-job通信模块源码分析)

    文章目录 背景 依赖 包结构 实现 WebSocketServer 业务handler WebSocketServerHandler 测试 xxl-job 源码中基于netty实现的http 总结 参 ...

  3. 基于netty4.x开发时间服务器

    在写代码之前 先了解下Reactor模型: Reactor单线程模型就是指所有的IO操作都在同一个NIO线程上面完成的,也就是IO处理线程是单线程的.NIO线程的职责是: (1)作为NIO服务端,接收 ...

  4. Internet 上可用的“简单网络时间协议”时间服务器列表

    Internet 上可用的"简单网络时间协议"时间服务器列表 在此公布一些Internet的公网时间服务器,大家可以快点同步时间哦:) Internet 上有两级(或两层)&quo ...

  5. WebSocket协议入门:WebSocket API

    HTML5连接性领域包括WebSocket.服务器发送事件和跨文档消息传递(Cross-Document Messaging)等技术.在HTML5之前,浏览器窗口和框架之间的通信由于安全的原因而受到限 ...

  6. NTP时间服务器简介

    NTP(Network Time Protocol) 网络时间协议,工作在UDP的123端口上.是用来使计算机时间同步化的一种协议,它可以使计算机对其服务器或时钟源(如石英钟,GPS等等)做同步化,它 ...

  7. NTP时间服务器介绍

    NTP服务器提供准确时间,首先要有准确的时间来源,这一时间应该是国际标准时间UTC. NTP获得UTC的时间来源可以是原子钟.天文台.卫星,也可以从Internet上获取.这样就有了准确而可靠的时间源 ...

  8. netty 游戏服务器框图_基于Netty和WebSocket协议实现Web端自动打印订单服务方法与流程...

    本发明涉及电子商务技术领域,尤其涉及一种基于netty和websocket协议实现web端自动打印订单服务方法. 背景技术: 电子商务是以信息网络技术为手段,以商品交换为中心的商务活动:也可理解为在互 ...

  9. 深入分析websocket协议,从3个方面设计网络应用层协议丨网络编程|网络IO|epoll|socket|网络协议丨c/c++linux服务器开发

    深入分析websocket协议,从3个方面设计网络应用层协议 视频讲解如下: 深入分析websocket协议,从3个方面设计网络应用层协议丨网络编程|网络IO|epoll|socket|网络协议丨c/ ...

最新文章

  1. Hyperledger Fabric 私有数据(1)概念
  2. NASA重金悬赏 太空尿片最佳解决方案
  3. 请讲一下浏览器从接收到一个URL,到最后展示出页面,经历了哪些过程
  4. 抢先试用ReSharper UnitRun™ 1.0
  5. Kali Linux 无线渗透测试入门指南 翻译完成!
  6. 【问题解决】解决 Android SDK下载和更新失败“Connection to https://dl-ssl.google.com refused”的问题
  7. 学习Oracle的三重境界
  8. 【转】 测试人员的职业规划 --整理标注
  9. sqli-labs(19)
  10. 有限元基础(一) Jacobian 矩阵和高斯积分
  11. 几大主流的前端框架(UI/JS)框架
  12. matlab PTB 学习笔记02——开启PTB设置
  13. 【领域泛化论文阅读】Birds of A Feather Flock Together:Category-Divergence Guidance for DomainAdaptiveSegmentat
  14. win8 计算机内存不足怎么办,如何解决Win8电脑内存不足的问题?
  15. 机器学习西瓜书第一章总结
  16. 【算法】离散傅里叶变换(DFT)
  17. Pair Project
  18. 知识图谱初探(二)三体人物关系图谱构建
  19. 2008年MBA联考考试大纲[综合]
  20. 基于LOAM框架的激光SLAM开源程序集合

热门文章

  1. 肠道核心菌属——普拉梭菌F. prausnitzii,预防炎症的下一代益生菌
  2. Xp0int2016新生杯CTF-writeup
  3. elasticsearch安装配置
  4. Spring Boot、Spring MVC、Spring:它们有什么区别?
  5. Pyinstaller 打包 Pytest项目及资源文件
  6. alsa 音频编程简单的例子 (总结)
  7. 【记录一次nginx转发 80端口无效】
  8. MySQL函数:ON UPDATE CURRENT_TIMESTAMP 与 CURRENT_TIMESTAMP
  9. 云渲染如何收费,云渲染哪个平台费用低?
  10. 优信拍集团php面试题_【优信拍怎么样?】-看准网