基于Netty的websocket的简单介绍

1、websocket简介

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

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

TCP连接是一种可靠的、面向连接的网络通信协议。它通过三次握手建立连接,然后通过数据包的传输和确认来保证数据的可靠性和顺序性。

在建立TCP连接时,客户端首先向服务器发送一个SYN(同步)包,服务器收到后回复一个SYN+ACK(同步+确认)包,客户端再回复一个ACK(确认)包,完成了三次握手,建立了连接。在连接建立后,双方可以通过发送和接收数据包进行通信。

发送方将数据分割成小的数据包,并为每个数据包添加序列号。接收方接收到数据包后进行确认,并按照序列号将数据包重新组装成完整的数据。

「WebSocket」可以双向通讯,它可以完成客户端到服务端以及服务端到客户端的双向推送的通讯工具。

2、其他类似的产品

因为「WebSocket」可以数据的实时推送,所以常用用推送一些实时变化的数据。在我们业务场景中大多数实现的服务端到客户端的单向推送,其实现的方式还有很多种。

  • 客户端轮询,如间隔n秒发送http请求,以保证拉取准实时的数据

  • 长轮询,保持长时间的http连接,超时之后继续轮询。具有代表性的就是SSE,chatgpt就是基于SSE实现的

  • 长链接,也就是socket连接

前两种都是短连接基于http协议的的,其中长轮询主要是设置请求头:

Connection: keep-alive

3、数据推送存在问题

  • 短轮询存在很多无效的请求,拉取的数据的间隔不好掌握,拉取的数据未必是实时的

  • 长轮询的超时时间难以掌控,如果设置成永久保持,那么页面关闭或退出,连接依然有效,浪费链接资源。

  • SSE是基于长轮询的,实现了断线重连,超时、异常的回调等。但是多开页面,断线重新,都会产品不同的客户端,做到精准推送需要管理好不同的客户端,客户端的增多可能会造成服务端的OOM,这些都是考虑的重点

  • websocket则存在粘包、拆包的问题以及客户端的异常关闭等

其中netty解决websocket中常见的问题。

4、基于Netty解决socket的问题

Netty 中提供一系列解决socket的方案。

4.1 Socket服务端
public void run() {
	EventLoopGroup bossGroup = new NioEventLoopGroup();
	EventLoopGroup workerGroup = new NioEventLoopGroup();
	try {
        // 创建Socket服务端
		ServerBootstrap b = new ServerBootstrap();
        // bossGroup辅助客户端的tcp连接请求, workGroup负责与客户端之前的读写操作
		b.group(bossGroup, workerGroup)
            // 设置NIO类型的channel
			.channel(NioServerSocketChannel.class)
			.childHandler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel channel) throws Exception {
					// ...
				}
			});

        // 配置完成,开始绑定server,通过调用sync同步方法阻塞直到绑定成功
		Channel channel = b.bind(port).sync().channel();
        // 对关闭通道进行监听
		channel.closeFuture().sync();
	} catch (InterruptedException e) {
		logger.error("webSocket server start error:" + e.getMessage());
	} finally {
		bossGroup.shutdownGracefully();
		workerGroup.shutdownGracefully();
	}
}

从样例代码中有几个关键的对象:

  • ServerBootstrap 这个是服务端的对象

  • NioServerSocketChannel 这个是服务端绑定的Channel类型

  • bind(port) 绑定服务端的端口

  • 使用双EventLoopGroup

4.2 Socket客户端
private void start() throws InterruptedException {
	EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
    // 创建客户端
	Bootstrap bootstrap = new Bootstrap();
    // 设置NIO类型的channel
	bootstrap.channel(NioSocketChannel.class);
	bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
	bootstrap.group(eventLoopGroup);
	
	bootstrap.handler(new ChannelInitializer<SocketChannel>() {
		@Override
		protected void initChannel(SocketChannel socketChannel)
				throws Exception {
			// ...
		}
	});
    // 连接
	ChannelFuture future = bootstrap.connect(host, port).sync();
	if (future.isSuccess()) {
		logger.info("connect server success");
	}

	NioSocketChannel channel = future.channel();
}

样例中的关键对象:

  • Bootstrap 创建客户端的对象

  • NioSocketChannel 客户端绑定的channel类型

  • connect(host, port) 客户端是用来连接服务端的

  • 只有一个EventLoopGroup

5、Netty解决的Socket问题的类

5.1 IdleStateHandler

读写空闲处理器,一般用来写空闲来发送心跳检测消息

    /**
     * Creates a new instance firing {@link IdleStateEvent}s.
     *
     * @param readerIdleTimeSeconds
     *        an {@link IdleStateEvent} whose state is {@link IdleState#READER_IDLE}
     *        will be triggered when no read was performed for the specified
     *        period of time.  Specify {@code 0} to disable.
     * @param writerIdleTimeSeconds
     *        an {@link IdleStateEvent} whose state is {@link IdleState#WRITER_IDLE}
     *        will be triggered when no write was performed for the specified
     *        period of time.  Specify {@code 0} to disable.
     * @param allIdleTimeSeconds
     *        an {@link IdleStateEvent} whose state is {@link IdleState#ALL_IDLE}
     *        will be triggered when neither read nor write was performed for
     *        the specified period of time.  Specify {@code 0} to disable.
     */
    public IdleStateHandler(
            int readerIdleTimeSeconds,
            int writerIdleTimeSeconds,
            int allIdleTimeSeconds) {

        this(readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds, TimeUnit.SECONDS);
    }

对应的Handler处理

需要继承SimpleChannelInboundHandler 或实现 ChannelInboundHandler接口, 重写或实现userEventTriggered 方法。

例:

public class NettyClientHandler extends SimpleChannelInboundHandler<?> {
    //利用写空闲发送心跳检测消息
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            switch (e.state()) {
				// 读空间
				case READER_IDLE// ...
					break;
				// 写空闲
                case WRITER_IDLE:
                    // ...
                    break;
				// 读写空闲	
				case ALL_IDLE:
					// ...
					break;
                default:
                    break;
            }
        }
    }
   
}
5.2 HttpServerCodec

Http请求解码器和Http响应的编码器合二为一。相当于HttpRequestDecoderHttpResponseEncoder 。用来处理Http请求的。

pipeline.addLast(new HttpServerCodec());
5.3 ChunkedWriteHandler

以快的方式写入,也就是大数据量的流式写入

pipeline.addLast(new ChunkedWriteHandler());
5.4 HttpObjectAggregator

聚合器,将一块块的数据聚合在一起,形成一条完整的数据

pipeline.addLast(new HttpObjectAggregator(64 * 1024));
5.3 拆包粘包解决方案
  • FixedLengthFrameDecoder 使用定长的报文来分包

  • DelimiterBasedFrameDecoder 添加特殊分隔符报文来分包

  • LineBasedFrameDecoder 数据未尾添加回车换行符来分包

  • LengthFieldBasedFrameDecoder 使用消息头和消息体来分包

  • StringDecoder 字符串解码器

  • StringEncoder 字符串编码器

  • ByteToMessageDecoder 如果想实现自己的半包解码器,实现该类

5.4 WebSocketServerProtocolHandler

订阅websocket的连接,也是webscoket的关键

pipeline.addLast(new WebSocketServerProtocolHandler("/ws"))

6、浏览器作为客户端

WebSocket一般的浏览器是直接支持的的。

let socket = new WebSocket('ws://localhost:8080/ws');
// 打开 连接
socket.addEventListener('open', function (event) {
    socket.send('Hello Server!');
});

// 监听动态 数据
socket.addEventListener('message', function (event) {
    console.log('Message from server ', event.data);
});

浏览器作为客户端时,浏览器已经处理了粘包、拆包分析。不需要专门的处理,数据是frame的形式发送的,frame中包含了完整数据的标识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/597911.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

4. FactoryTalk View SE按钮弹出二次确认

在按钮界面–按钮属性–添加释放动作–选择需要确认–配置–确定。 &#xff08;如果是用变量连接的比如需要输入密码等等选择使用变量&#xff09; 这样就完成了二次确认的窗口设置。

106短信群发平台:拓客拉新、商品促销,效果究竟如何?一试便知!

106短信群发平台在拓客拉新和商品促销方面的效果是非常显著的。 首先&#xff0c;从发送速度和到达率来看&#xff0c;106短信平台表现优秀。无论是节假日还是平日&#xff0c;其发送速度都能保持在一个较快的水平&#xff0c;这对于需要及时到达的营销信息尤为重要。同时&…

Leetcode—1991. 找到数组的中间位置【简单】

2024每日刷题&#xff08;129&#xff09; Leetcode—1991. 找到数组的中间位置 实现代码 class Solution { public:int findMiddleIndex(vector<int>& nums) {int sum accumulate(nums.begin(), nums.end(), 0);int prefix 0;for(int i 0; i < nums.size();…

第十三章 计算机网络

这里写目录标题 1.网络设备2.协议簇2.1电子邮件(传输层)2.2地址解析(网际层)2.3DHCP(动态主动配置协议)2.4URL(统一资源定位器)2.5IP地址和子网掩码 1.网络设备 物理层&#xff1a;中继器&#xff0c;集线器(多路中继器) 数据链路层&#xff1a;网桥&#xff0c;交换机(多端口…

软件FMEA的时机:架构设计、详设阶段——FMEA软件

免费试用FMEA软件-免费版-SunFMEA 软件FMEA&#xff08;故障模式与影响分析&#xff09;是一种预防性的质量工具&#xff0c;旨在识别软件中可能存在的故障模式&#xff0c;并分析其对系统性能、安全性和可靠性的影响。在软件开发生命周期中&#xff0c;选择适当的时机进行FME…

[Docker]容器的网络类型以及云计算

目录 知识梗概 1、常用命令2 2、容器的网络类型 3、云计算 4、云计算服务的几种主要模式 知识梗概 1、常用命令2 上一篇已经学了一些常用的命令&#xff0c;这里补充两个&#xff1a; 导出镜像文件&#xff1a;[rootdocker ~]# docker save -o nginx.tar nginx:laster 导…

rust调用SQLite实例

rusqlite库介绍 Rusqlite是一个用Rust编写的SQLite库&#xff0c;它提供了对SQLite数据库的操作功能。Rusqlite的设计目标是提供一个简洁易用的API&#xff0c;以便于Rust程序员能够方便地访问和操作SQLite数据库。 Rusqlite的主要特点包括&#xff1a; 遵循Rust的类型系统和…

用滑动条改变字体的大小(简单好抄)

1.首先在屏幕中添加一个滑动条和你要改变字体大小的文本&#xff08;用新版的&#xff09; 2.点击滑动条设置value的最大值和最小值 3.编写脚本 using System.ComponentModel; using TMPro; using UnityEngine; using UnityEngine.UI;public class FontSizeSlider : MonoBehav…

LeetCode 面试经典150题 228.汇总区间

题目&#xff1a; 给定一个 无重复元素 的 有序 整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说&#xff0c;nums 的每个元素都恰好被某个区间范围所覆盖&#xff0c;并且不存在属于某个范围但不属于 nums 的数字 x 。 列表中的每个区…

IEEE(TOP),CCF推荐,5本毕业神刊,最快7天录用!指标优秀

本期盘点计算机领域超顺快刊&#xff0c;涵盖IEEE1区TOP、CCF推荐SCIE&#xff0c;期刊指标优秀&#xff0c;审稿周期短&#xff0c;质量稳定&#xff0c;有意向作者请看下文&#xff1a; IEEE旗下1区&#xff08;TOP&#xff09; 1 期刊简介 ✅出版社&#xff1a;IEEE ✅影…

Java17的崛起——newrelic的2024 年 Java 生态系统状

newrelic 2024 年 Java 生态系统状况 原文PDF&#xff1a;点我下载 生产中最常用的 Java 版本 Oracle 每六个月发布一次新的 Java 版本&#xff08;通常是在 3 月和 9 月&#xff09;&#xff0c;每个版本都包含一些新功能和错误修复。每两年&#xff0c;Oracle 都会推出一…

Linux环境下部署vsftp+mysql用户认证

安装mysql(不要使用红帽的RPM版的mysql) 使用编译或静态库安装mysql 1、编译安装pam_mysql 下载软件&#xff1a; http://downloads.sourceforge.net/project/pam-mysql/pam-mysql/0.7RC1/pam_mysql-0.7RC1.tar.gz?rhttp%3A%2F%2Fsourceforge.net%2Fprojects%2Fpam-mysql%2F…

数据结构_顺序表(动态)和链表(带头双向循环)的区别

✨✨所属专栏&#xff1a;数据结构✨✨ ✨✨作者主页&#xff1a;嶔某✨✨ 储存空间 我们知道顺序表的实质就是一个数组&#xff0c;数组的物理地址是连续的&#xff1b;而链表是由一个个的节点组成的&#xff0c;物理地址不一定连续、因为在malloc空间的时候不能保证&#xf…

JETBRAINS IDES 分享一个2099通用试用码!IDEA 2024 版 ,支持一键升级

文章目录 废话不多说上教程&#xff1a;&#xff08;动画教程 图文教程&#xff09;一、动画教程激活 与 升级&#xff08;至最新版本&#xff09; 二、图文教程 &#xff08;推荐&#xff09;Stage 1.下载安装 toolbox-app&#xff08;全家桶管理工具&#xff09;Stage 2 : 下…

【计算机科学速成课】笔记四

文章目录 19.内存&存储介质课程引出——内存与存储器的区别纸带存储磁芯存储磁带、磁鼓存储磁盘&#xff08;硬盘&#xff09;存储软盘存储光盘存储&#xff08;CD&DVD&#xff09;固态硬盘存储 20.文件系统课程引出——文件格式.txt文本文件.wav 音频文件.bmp位图文件…

Seal^_^【送书活动第3期】——《Hadoop大数据分析技术》

Seal^_^【送书活动第3期】——《Hadoop大数据分析技术》 一、参与方式二、作者荐语三、图书简介四、本期推荐图书4.1 前 言4.2 本书内容4.3 本书目的4.4 本书适合的读者4.5 配套源码、PPT课件等资源下载 五、目 录六、&#x1f6d2; 链接直达 Hadoop框架入门书&#xff0c;可当…

明星中药企业系列洞察(四)丨从超级单品到健康医药集团,云南白药如何打造自己的多元宇宙?

前不久&#xff0c;云南白药发布的2023年年报显示&#xff0c;报告期内&#xff0c;云南白药实现营业收入391.11亿元&#xff0c;同比增长7.19%&#xff0c;创同期历史新高。同时&#xff0c;公司计划每10股派发现金红利20.77元&#xff08;含税&#xff09;&#xff0c;分红总…

17.Blender RC大佬EEVEE皮肤节点预设导入

如何添加节点预设 在底下的左下角打开Geometry Node Editor 选中正方体&#xff0c;点击新建 当鼠标指针在两个模块之间&#xff0c;是十字的样子时 可以拖出一个新的板块 然后打开文件浏览器 找到节点预设然后拖入到底下的节点编辑界面就可以了或者是blend文件&#xf…

Go Web 开发 Demo【用户登录、注册、验证】

前言 这篇文章主要是学习怎么用 Go 语言&#xff08;Gin&#xff09;开发Web程序&#xff0c;前端太弱了&#xff0c;得好好补补课&#xff0c;完了再来更新。 1、环境准备 新建项目&#xff0c;生成 go.mod 文件&#xff1a; 出现报错&#xff1a;go: modules disabled by G…

vue cli 自定义项目架子,vue自定义项目架子,超详细

脚手架Vue CLI基本介绍&#xff1a; Vue CLI 是Vue官方提供的一个全局命令工具 可以帮助我们快速创建一个开发Vue项目的标准化基础架子【集成了webpack配置】 脚手架优点&#xff1a; 开箱即用&#xff0c;零配置内置babel等工具标准化的webpack配置 脚手架 VueCLI相关命令…