场景

Netty中实现多客户端连接与通信-以实现聊天室群聊功能为例(附代码下载):

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108623306

上面讲了使用使用Socket搭建多客户端的连接与通信。

那么如果在Netty中使用WebSocket进行长连接通信要怎么实现。

WebSocket

现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

WebSocket是一种在单个TCP连接上进行全双工通信的协议。

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。

当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

WebSocket 属性

以下是 WebSocket 对象的属性。假定我们使用了以上代码创建了 Socket 对象:

属性 描述
Socket.readyState

只读属性 readyState 表示连接状态,可以是以下值:

  • 0 - 表示连接尚未建立。

  • 1 - 表示连接已建立,可以进行通信。

  • 2 - 表示连接正在进行关闭。

  • 3 - 表示连接已经关闭或者连接不能打开。

Socket.bufferedAmount

只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。


WebSocket 事件

以下是 WebSocket 对象的相关事件。假定我们使用了以上代码创建了 Socket 对象:

事件 事件处理程序 描述
open Socket.onopen 连接建立时触发
message Socket.onmessage 客户端接收服务端数据时触发
error Socket.onerror 通信发生错误时触发
close Socket.onclose 连接关闭时触发

WebSocket 方法

以下是 WebSocket 对象的相关方法。假定我们使用了以上代码创建了 Socket 对象:

方法 描述
Socket.send()

使用连接发送数据

Socket.close()

关闭连接

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。

实现

在IDEA中搭建好Netty的项目并引入环境可以参照如下:

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108592418

在此基础上,在src下新建包com.badao.NettyWebSocket

然后新建服务端类WebSocketServer

package com.badao.NettyWebSocket;import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;public class WebSocketServer {public static void main(String[] args) throws  Exception{EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try{ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new WebSocketInitializer());//绑定端口ChannelFuture channelFuture = serverBootstrap.bind(70).sync();channelFuture.channel().closeFuture().sync();}finally {//关闭事件组bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}

服务端的搭建在上面已经讲解,这里又添加了Netty自带的日志处理器LoggingHandler

然后又添加了自定义的初始化器WebSocketInitializer

所以新建类WebSocketInitializer

package com.badao.NettyWebSocket;import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;public class WebSocketInitializer  extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new HttpServerCodec());pipeline.addLast(new ChunkedWriteHandler());pipeline.addLast(new HttpObjectAggregator(8192));pipeline.addLast(new WebSocketServerProtocolHandler("/badao"));pipeline.addLast(new WebSocketHandler());}
}

因为Netty也是基于Http的所以这里需要添加HttpServerCodec处理器等。

要想实现WebSocket功能,主要是添加了WebSocketServerProtocolHandler这个WebSocket服务端协议处理器。注意这里的参数需要添加一个WebSocket的路径,这里是/badao

最后添加自定义的处理器WebSocketHandler 用来做具体的处理

所以新建类WebSocketHandler

package com.badao.NettyWebSocket;import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;import java.time.LocalDateTime;public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {System.out.println("收到消息:"+msg.text());ctx.channel().writeAndFlush(new TextWebSocketFrame("WebSocket服务端在"+ LocalDateTime.now()+"发送消息(公众号:霸道的程序猿)"));}@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {System.out.println("handlerAdded:"+ctx.channel().id().asLongText());}@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception {System.out.println("handlerRemoved:"+ctx.channel().id().asLongText());}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {System.out.println("异常发生");ctx.close();}
}

使其继承SimpleChannelInboundHandler注意此时的泛型类型为TextWebSocketFrame

然后重写channelRead0方法用来对收到数据时进行处理

    @Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {System.out.println("收到消息:"+msg.text());ctx.channel().writeAndFlush(new TextWebSocketFrame("WebSocket服务端在"+ LocalDateTime.now()+"发送消息(公众号:霸道的程序猿)"));}

在服务端将收到的消息进行输出并给客户端发送数据。

然后重写handlerAdded方法,在客户端与服务端建立连接时进行操作

    @Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {System.out.println("handlerAdded:"+ctx.channel().id().asLongText());}

这里通过通道的id方法的asLongText方法获取连接的唯一标志。

然后在服务端输出。

同理重写handlerRemoved方法,在断掉连接时将连接的唯一标志进行输出。

    @Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception {System.out.println("handlerRemoved:"+ctx.channel().id().asLongText());}

最后重写出现异常时的处理方法,在出现异常时将连接关闭。

    @Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {System.out.println("异常发生");ctx.close();}

至此WebSocket服务端搭建完成,然后客户端通过JS就能实现。

在项目目录下src下新建webapp目录,在此目录下新建badao.html

修改html的代码为

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>公众号:霸道的程序猿</title>
</head>
<body>
<script type="text/javascript">var socket;if(window.WebSocket){socket = new WebSocket("ws://localhost:70/badao")socket.onmessage=function (ev) {var ta = document.getElementById("responseText");ta.value = ta.value+"\n"+ev.data;}socket.onopen = function (ev) {var ta = document.getElementById("responseText");ta.value = "连接开启";}socket.onclose = function (ev) {var ta = document.getElementById("responseText");ta.value = ta.value+"\n连接关闭";}}else{alert("当前浏览器不支持WebSocket")}function send(message) {if(!window.WebSocket){return;}else{if(socket.readyState = WebSocket.OPEN){socket.send(message);}else{alert("连接尚未开启");}}}
</script>
<form><textarea name="message" style="width: 400px;height: 200px"></textarea><input type="button" value="发送数据" onclick="send(this.form.message.value)"><h3>服务端输出:</h3><textarea id="responseText" style="width: 400px;height: 200px"></textarea>
</form>
</body>
</html>

在js中通过windows.WebSocket判断是否支持WebSocket

如果支持则

socket = new WebSocket("ws://localhost:70/badao")

建立连接,url的写法前面的ws://是固定的类似http://

后面的是跟的ip:端口号/上面配置的WebSocket路径

然后就是以这个WebSocket对象为中心进行连接和数据的显示。

下面的回调方法onopen会在建立连接成功后回调,onclose会在断掉连接后回调,

onmessage会在收到服务端发送的数据时回调并通过ev.data获取数据。

客户端向服务端发送数据时调用的是socket的send方法,通过

if(socket.readyState = WebSocket.OPEN)

判断连接已经成功建立。

实现长连接通信

运行WebSocketServer的main方法,然后在badao.html上右击选择运行

建立连接成功后会在服务端输出连接的id,在客户端会显示连接开启。

此时如果刷新浏览器,服务端会输出一次断开连接和建立连接

再将服务端停掉,客户端会输出连接关闭

再重新启动服务端,在上面的输入框输入内容并点击发送数据

服务端会收到消息并输出,并向客户端发送一个消息。

继续发送也是如此

示例代码下载

https://download.csdn.net/download/BADAO_LIUMANG_QIZHI/12853829

Netty中使用WebSocket实现服务端与客户端的长连接通信发送消息相关推荐

  1. 使用HTML5的WebSocket实现服务端和客户端数据通信(有演示和源码)

    WebSocket协议是基于TCP的一种新的网络协议.WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术.依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信. ...

  2. Netty 通过 WebSocket 编程实现服务器和客户端全双工长连接<2021SC@SDUSC>

    2021SC@SDUSC Netty 通过 WebSocket 编程实现服务器和客户端全双工长连接 实例要求: Http 协议是无状态的, 浏览器和服务器间的请求响应一次,下一次会重新创建连接. 要求 ...

  3. ssm配置socket_ssm框架中集成websocket实现服务端主动向客户端发送消息

    找了很多配置文档及实例说明,也还是没能成功,最终在csdn博客中发现了基于stomp的消息推送的文章, 下面整理自csdn博客,https://blog.csdn.net/u013627689/art ...

  4. js ws 状态_node.js中ws模块创建服务端和客户端,网页WebSocket客户端

    首先下载websocket模块,命令行输入 npm install ws 1.node.js中ws模块创建服务端 // 加载node上websocket模块 ws; var ws = require( ...

  5. node.js中ws模块创建服务端和客户端,网页WebSocket客户端

    首先下载websocket模块,命令行输入 npm install ws 1.node.js中ws模块创建服务端 // 加载node上websocket模块 ws; var ws = require( ...

  6. Netty学习笔记(二) 实现服务端和客户端

    在Netty学习笔记(一) 实现DISCARD服务中,我们使用Netty和Python实现了简单的丢弃DISCARD服务,这篇,我们使用Netty实现服务端和客户端交互的需求. 前置工作 开发环境 J ...

  7. 使用WebSocket实现服务端和客户端的通信

    开发中经常会有这样的使用场景.如某个用户在一个数据上做了xx操作, 与该数据相关的用户在线上的话,需要实时接收到一条信息. 这种可以使用WebSocket来实现. 另外,对于消息,可以定义一个类进行固 ...

  8. springboot+websocket实现服务端、客户端

    一.引言 小编最近一直在使用springboot框架开发项目,毕竟现在很多公司都在采用此框架,之后小编也会陆续写关于springboot开发常用功能的文章. 什么场景下会要使用到websocket的呢 ...

  9. 【Android WebSocket】Android 端 WebSocket 基本用法 ( 添加依赖和权限 | 创建 WebSocketClient 客户端类 | 建立连接并发送消息 )

    文章目录 一.添加依赖和权限 二.创建 WebSocketClient 客户端类 三.建立连接并发送消息 使用 https://github.com/TooTallNate/Java-WebSocke ...

  10. netty中的引导Bootstrap服务端

    引导一个应用程序是指对它进行配置,并使它运行起来的过程. 一.Bootstrap 类 引导类的层次结构包括一个抽象的父类和两个具体的引导子类,如图 8-1 所示 服务器致力于使用一个父 Channel ...

最新文章

  1. 面向B端市场,Mana VR团队将推出VR交互产品
  2. 程序员一夜暴富捷径?不,别被轻易骗进“独角兽”
  3. boost::sort模块实现使用不区分大小写的字符串键对结构进行排序的示例
  4. react api_如何在WordPress REST API之上构建React应用
  5. 京东也准备向社区团购进发了?
  6. [转]PlantUML画类图、流程图、时序图使用详解
  7. Codeforces Round #296 (Div. 2) C. Glass Carving [ set+multiset ]
  8. 201809-1—卖菜
  9. 客户关系管理之会员管理(转)
  10. t470键盘拆解_看完你就想买——绝对良心级做工品质的ThinkPad T470拆解
  11. 基于java+springboot+mybatis+laiyu实现学科竞赛管理系统《建议收藏》
  12. Javascript实现全屏阅读和复制功能
  13. 揭秘网站的seo技术 ---seo与seoer 王泽宾
  14. h5/web遮罩弹窗
  15. txt文本怎么去除重复项
  16. 地下城与勇士鬼剑士觉醒java_地下城与勇士之鬼剑士觉醒单机版
  17. CMOS反相器版图设计
  18. 人大金仓(Kingbase)数据库迁移——KDMS工具(人大金仓数据库迁移工具迁移失败可使用此方法)
  19. 逻辑卷增加根目录空间
  20. 训练Cityscapes

热门文章

  1. win10网络适配器不见了_win10没有网络适配器怎么办
  2. dhcp服务器不显示mac地址,利用MAC地址解决无法获得DHCP动态地址分配问题
  3. Java 第 34 课 1365. 有多少小于当前数字的数字 1331. 数组序号转换
  4. 【知识图谱】Neo4j 导入数据构建知识图谱的三种方法
  5. Magento常用插件整理收集
  6. mybatis plus 出现 Invalid bound statement (not found)
  7. python爬取电影评分_python爬取豆瓣电影排行榜(requests)的示例代码
  8. 零基础应该怎么学剪辑,大概要学多长时间?在磨金石教育学靠谱吗?
  9. Java为PDF文档加密
  10. 质量团队在VUCA时代如何走?