http协议是无状态的,因此导致客户端每次通信都需要携带标识(session)给服务端,以此来识别是哪个客户端发送过来的信息。但是当服务端主动推送给客户端时就无法实现了,因为服务端不知道客户端在哪,此时通常的做法时客户端轮询服务端,不停的给服务端发送消息,来接受服务端信息。很明显这种方式会浪费大量的资源,并且HTTP消息本身携带的数据就比较大,频繁发送更会增加网络负担。websocket就是为了解决这个问题而诞生的。

一、websocket

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。websocket的特点是事件驱动、异步、使用ws或者wss协议的客户端socket、能够实现真正意义上的推送功能。通信流程:

但是websocket本身依赖于tomcat,然而tomcat并发量不大,连接数低,会导致出现断连的情况,因此对于websocket通信要求不高的可以直接使用tomcat即可,但是遇到高并发就难以支持了。通常会选用Netty作为通信的服务端。

二、Netty

Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。Netty是基于Java NIO实现的异步通信框架,其主要特点是简单,要比原生的JavaNIO开发方便很多,同时Netty封装了大量好用的组件,方便开发。下面基于Netty实现websocket通信。

三、实现websocket通信

public class WebSocketServer {public void run() {// 服务端启动辅助类,用于设置TCP相关参数ServerBootstrap bootstrap = new ServerBootstrap();// 获取Reactor线程池EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workGroup = new NioEventLoopGroup();// 设置为主从线程模型bootstrap.group(bossGroup, workGroup)// 设置服务端NIO通信类型.channel(NioServerSocketChannel.class)// 设置ChannelPipeline,也就是业务职责链,由处理的Handler串联而成,由从线程池处理.childHandler(new ChannelInitializer<Channel>() {// 添加处理的Handler,通常包括消息编解码、业务处理,也可以是日志、权限、过滤等@Overrideprotected void initChannel(Channel ch) throws Exception {// 获取职责链ChannelPipeline pipeline = ch.pipeline();// pipeline.addLast("http-codec", new HttpServerCodec());pipeline.addLast("aggregator", new HttpObjectAggregator(65535));pipeline.addLast("http-chunked", new ChunkedWriteHandler());pipeline.addLast("handler", new WebSocketHandler());}})// bootstrap 还可以设置TCP参数,根据需要可以分别设置主线程池和从线程池参数,来优化服务端性能。// 其中主线程池使用option方法来设置,从线程池使用childOption方法设置。// backlog表示主线程池中在套接口排队的最大数量,队列由未连接队列(三次握手未完成的)和已连接队列.option(ChannelOption.SO_BACKLOG, 5)// 表示连接保活,相当于心跳机制,默认为7200s.childOption(ChannelOption.SO_KEEPALIVE, true);try {// 绑定端口,启动select线程,轮询监听channel事件,监听到事件之后就会交给从线程池处理Channel channel = bootstrap.bind(8081).sync().channel();// 等待服务端口关闭channel.closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {// 优雅退出,释放线程池资源bossGroup.shutdownGracefully();workGroup.shutdownGracefully();}}public static void main(String[] args) {new WebSocketServer().run();}}
public class WebSocketHandler extends ChannelInboundHandlerAdapter{//用于websocket握手的处理类private WebSocketServerHandshaker handshaker;@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg)throws Exception {if (msg instanceof FullHttpRequest) {// websocket连接请求handleHttpRequest(ctx, (FullHttpRequest)msg);} else if (msg instanceof WebSocketFrame) {// websocket业务处理handleWebSocketRequest(ctx, (WebSocketFrame)msg);}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {ctx.close();}private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {// Http解码失败,向服务器指定传输的协议为Upgrade:websocketif (!req.decoderResult().isSuccess() || (!"websocket".equals(req.headers().get("Upgrade")))) {sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));return;}// 握手相应处理,创建websocket握手的工厂类,WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws://localhost:8081/ws", null, false);// 根据工厂类和HTTP请求创建握手类handshaker = wsFactory.newHandshaker(req);if (handshaker == null) {// 不支持websocketWebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());} else {// 通过它构造握手响应消息返回给客户端handshaker.handshake(ctx.channel(), req);}}private void handleWebSocketRequest(ChannelHandlerContext ctx, WebSocketFrame req) throws Exception {if (req instanceof CloseWebSocketFrame) {// 关闭websocket连接handshaker.close(ctx.channel(), (CloseWebSocketFrame)req.retain());return;}if (req instanceof PingWebSocketFrame) {ctx.channel().write(new PongWebSocketFrame(req.content().retain()));return;}if (!(req instanceof TextWebSocketFrame)) {throw new UnsupportedOperationException("当前只支持文本消息,不支持二进制消息");}if (ctx == null || this.handshaker == null || ctx.isRemoved()) {throw new Exception("尚未握手成功,无法向客户端发送WebSocket消息");}ctx.channel().write(new TextWebSocketFrame(((TextWebSocketFrame)req).text()));}private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {// BAD_REQUEST(400) 客户端请求错误返回的应答消息if (res.status().code() != 200) {// 将返回的状态码放入缓存中,Unpooled没有使用缓存池ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);res.content().writeBytes(buf);buf.release();HttpUtil.setContentLength(res, res.content().readableBytes());}// 发送应答消息ChannelFuture cf = ctx.channel().writeAndFlush(res);// 非法连接直接关闭连接if (!HttpUtil.isKeepAlive(req) || res.status().code() != 200) {cf.addListener(ChannelFutureListener.CLOSE);}}}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Chat</title>
</head>
<body><script type="text/javascript">var socket;if (!window.WebSocket) {window.WebSocket = window.MozWebSocket;}if (window.WebSocket) {socket = new WebSocket("ws://localhost:8081/ws");socket.onopen = function(event) {var ta = document.getElementById('responseText');ta.value = "连接开启!";};socket.onclose = function(event) {var ta = document.getElementById('responseText');ta.value = ta.value + "连接被关闭";};socket.onmessage = function(event) {var ta = document.getElementById('responseText');ta.value = ta.value + '\n' + event.data;};} else {alert("你的浏览器不支持 WebSocket!");}function send(message) {if (!window.WebSocket) {return;}if (socket.readyState == WebSocket.OPEN) {socket.send(message);} else {alert("连接没有开启.");}}</script><form οnsubmit="return false;"><h3>WebSocket 聊天室:</h3><textarea id="responseText" style="width: 500px; height: 300px;"></textarea><br> <input type="text" name="message"  style="width: 300px" value="Welcome to www.waylau.com"><input type="button" value="发送消息" οnclick="send(this.form.message.value)"><input type="button" οnclick="javascript:document.getElementById('responseText').value=''" value="清空聊天记录"></form><br> <br>
</body>
</html>

Netty作为服务端的websocket通信相关推荐

  1. 多线程服务端和客户端通信

    ❤️强烈推荐人工智能学习网站❤️ 在不同的机器上可以用TCP进行通信,在同一台机器上也可以,用客户端/服务端模式通信耦合度更低,golang示例多线程服务端和客户端通信,用C++写也可以 packag ...

  2. 原理剖析-Netty之服务端启动工作原理分析(上)

    一.大致介绍 1.Netty这个词,对于熟悉并发的童鞋一点都不陌生,它是一个异步事件驱动型的网络通信框架: 2.使用Netty不需要我们关注过多NIO的API操作,简简单单的使用即可,非常方便,开发门 ...

  3. C#Winform窗体实现服务端和客户端通信例子(TCP/IP)

    Winform窗体实现服务端和客户端通信的例子,是参考这个地址 http://www.cnblogs.com/longwu/archive/2011/08/25/2153636.html 进行了一些异 ...

  4. Qt:Qt实现Winsock网络编程—TCP服务端和客户端通信(多线程)

    Qt实现Winsock网络编程-TCP服务端和客户端通信(多线程) 前言 感觉Winsock网络编程的api其实和Linux下网络编程的api非常像,其实和其他编程语言的网络编程都差不太多.博主用Qt ...

  5. [笨木头FireFly 03]完整的服务端和客户端通信

    #PS: 其实这篇文件是2013.10.12写完的,一直没发布,因为从那天起,我又跑回去折腾客户端的东西了(打算用Cocos2d-x3.0做下一个游戏),以及我的老游戏的维护和更新.总之各种借口(小若 ...

  6. Netty实现服务端客户端长连接通讯及心跳检测

    通过netty实现服务端与客户端的长连接通讯,及心跳检测. 基本思路:netty服务端通过一个Map保存所有连接上来的客户端SocketChannel,客户端的Id作为Map的key.每次服务器端如果 ...

  7. Websocket服务端和客户端通信(WSS、WS)

    前端和后端之间的通讯 一.简介 前端为客户端(Client),后端为服务端(Server) 具体操作步骤为: 1.运行 Server 目录下的 --> WebsocketServerWss_Ws ...

  8. netty tcp服务端主动断开客户端_【Netty】服务端和客户端

    欢迎关注公众号:[爱编程] 如果有需要后台回复2019赠送1T的学习资料哦!! 本文是基于Netty4.1.36进行分析 服务端 Netty服务端的启动代码基本都是如下: private void s ...

  9. Netty入门系列(1) --使用Netty搭建服务端和客户端

    引言 前面我们介绍了网络一些基本的概念,虽然说这些很难吧,但是至少要做到理解吧.有了之前的基础,我们来正式揭开Netty这神秘的面纱就会简单很多. 服务端 public class PrintServ ...

最新文章

  1. 2022-2028年中国客厅经济深度调研及投资前景预测报告
  2. python中可以用中文作为变量-在Python 3.x中可以使用中文作为变量名。
  3. hdu1978 简单记忆化搜索
  4. 浅谈用户体验的 4 个维度
  5. 运用java集合Collections对List进行max和min操作
  6. clickhouse原理解析与应用实践_编程好书推荐《Redis 深度历险:核心原理与应用实践》...
  7. 深入业务成为更好的软件架构师——信息化建设图鉴一二例
  8. 10年老电脑如何提速_电脑越用越卡?如何简单升级,让你的旧笔记本瞬间提速...
  9. php artisan 计划任务,Laravel 定时任务 任务调度 可手动执行
  10. linux下使用odbc连接mysql_Linux环境下通过ODBC访问MSSql Server
  11. python的tab自动补全
  12. Hinton胶囊网络后最新研究:用“在线蒸馏”训练大规模分布式神经网络
  13. php pmt,关于光电倍增管(PMT)模块的选型与使用
  14. Y-我的PPT监控之流媒体服务器的搭建
  15. 计算机网络中的ping什么意思,PING命令是什么?PING使用方法和参数详解
  16. 修改XAMPP启动mysql报错Port 3306 in use by D:\xampp\mysql\bin\mysqld!
  17. 武学大陆-为啥要学IT绝世武功
  18. 开启xmp1还是2_在DLSS2.0技术的加持下,游戏开启光线追踪的硬件需求是否会大大降低?...
  19. 70年代生人的80年代
  20. 小城里的“明星”产业,有微信云托管保驾护航

热门文章

  1. 浪涌保护器,信号浪涌保护器的原理和作用
  2. 2022年中国互联网婚恋交友行业发展现状及重点交友平台对比分析:百合佳缘优势明显[图]
  3. broadcm_40181 wifi 驱动分析
  4. 火狐浏览器调试js技巧_充分利用Firefox的最佳技巧和调整
  5. c语言修仙指针,C语言修仙
  6. 全球森林、土地利用、耕地数据下载
  7. 1到20的阶乘之和是多少
  8. MySQL零基础从入门到精通(函数篇)
  9. 深度学习论文翻译解析(五):Siamese Neural Networks for One-shot Image Recognition
  10. php的按钮submit,html5中submit是按钮么