Java NIO实现WebSocket服务器

2023-11-19

简介

在HTTP请求中,服务器往往处于被动的一方,通常都是客户端向服务器发送请求时,服务器才会做出响应,服务器并不会主动向客户端推送消息。因此WebSocket API就为此诞生。WebSocket API是HTML5中的一大特色,能够使得建立连接的双方在任意时刻相互推送消息,这意味着不同于HTTP,服务器服务器也可以主动向客户端推送消息了。

关于WebSocket的介绍,可以参考下一篇博文http://blog.csdn.net/zwto1/article/details/52493119#websocket%E5%8E%9F%E7%90%86

WebSocket协议的格式

为了实现一个能与H5的WebSocket API通信的服务器,我们需要先熟悉WebSocket数据包的格式。定的格式。

握手数据包

在一个连接建立以后,建立连接的双方才可以互相推送消息。双方通过握手即可建立一个连接。握手数据包的格式如下:

客户端向服务器发起请求

这里写图片描述

可以见到,客户端请求连接建立的数据包是一个字符串,而且第一行表明这实际上是一个HTTP报文。其中Connection: Upgrade以及Upgrade: websocket两字段就是用来告知服务器这是一个WebSocket握手请求。

服务器还要关心的一个字段是Sec-WebSocket-Key(倒数第二行),其值是一个随机base64字符串,服务器怎么处理该字符串请往下看。

服务器回应请求

这里写图片描述

可以看到HTTP状态码为101,同样,服务端也带有Connection和Upgrade字段来表明这是一个WebSocket数据包。

Sec-WebSocket-Accept字段是对请求报文中Sec-WebSocket-Key字段进行摘要运算的结果。其运算过程如下
1、将Sec-WebSocket-Key字段的值与字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11拼接。
2、对拼接后的字符串进行sha1运算,得到160位摘要(二进制)。
3、以base64的形式表示得到的摘要。
客户端会进行同样的运算,并且与服务器返回来的字段作对比,如果发现二者不相同,连接就无法建立了。

通信数据帧

通信数据帧的格式如下(参考官方文档https://www.rfc-editor.org/rfc/rfc6455.txt
这里写图片描述
其中各个字段的含义如下
FIN: 1bit,表示这是否为分片的最后一个数据帧。这是考虑到发送的数据有可能被分片的情况,如果存在分片,将此字段置1就表明这是最后一个分片。如果不存在分片,此字段恒为1。因为只有一个分片就一定是最后一个分片。

RSV1, RSV2, RSV3: 各1bit,全0。现在暂时用不上,为了将来可能用于功能拓展保留的字段。

Opcode: 4bits
指出数据的类型,值的解释如下

含义
0x0 附加数据帧
0x1 文本数据帧
0x2 二进制数据帧
0x3-0x7 暂无定义
0x8 关闭连接
0x9 表示ping
0xA 表示pong
0aB-0xF 暂无定义

MASK: 1bit
表明是否对数据进行掩码运算,置1表示使用掩码。从客户端向服务器发送的数据必须使用掩码。

Payload length: 7 bits, 7+16 bits, or 7+64 bits
表明数据的长度。
如果长度在0-125内,这7bits就表示数据的长度;
如果值为126,紧接着后面2字节(16bits)才表示数据的长度;
如果值为127,后面8字节(64bits)表示数据的长度。

Masking-key: 无 或 4 字节
如果掩码字段(MASK)置0,就不需要Masking-key。如果掩码字段为1,这4字节就是Masking-key,用它与数据部分进行异或运算。

Payload Data: 数据部分,长度可变。

关于其他详细说明可以参考官方文档,例如消息分片规则等。

实现一个WebSocket服务器(群聊天室例子)

为了更加深刻的理解这样一个协议,这里没有使用Java已经封装好操作的类库。

基于NIO监听端口

基于NIO中的ServerSocketChannel,实现一个接收并读取Socket内容的服务端套路如下。


public class WebSocketServer {
   

    private Selector serverSelector;
    private WebSocketListener socketListener;
    private boolean isRunning = true;

    public WebSocketServer(int serverPort, WebSocketListener socketListener) throws IOException {
        //初始化ServerSocketChannel
        ServerSocketChannel serverSocketChannel =
                ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(serverPort));
        serverSocketChannel.configureBlocking(false);

        //创建选择器
        serverSelector = Selector.open();

        //注册ServerSocketChannel的ACCEPT事件至选择器
        serverSocketChannel.register(serverSelector, SelectionKey.OP_ACCEPT);
        this.socketListener = socketListener;
    }

    public void run() throws IOException {
        while (isRunning) {
            int selectCount = serverSelector.select();
            if (selectCount == 0)
                continue;

            Iterator<SelectionKey> iterator = serverSelector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey selectKey = iterator.next();

                if (selectKey.isAcceptable()) {

                    //ACCEPT就绪,此时调用ServerSocketChannel的accept()方法可获得连接的SocketChannel对象,将其READ事件注册到选择器,就可以读取内容了。
                    ServerS
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java NIO实现WebSocket服务器 的相关文章

随机推荐

  • 安装vmware tools时,kernel版本不匹配问题的解决方法

    安装vmware tools 的时候 提示找不到C header files 此种情况下 按以下步骤操作 1 内核安装完毕后 需要用这个命令确定内核 C header 的安装目录 ls d usr src kernels uname r i
  • 怎样知道自己适不适合做程序员

    编程是一门非常有技术含量的手艺活 待遇和福利相对来说较为丰厚 由于种种原因想要转行做程序员的人 总会有这样的困惑 我是否适合做程序员呢 其实做为一个开发者 有一个学习的氛围跟一个交流圈子特别重要这里我推荐一个C语言C 交流群58365041
  • 全文检索几种词向量模型

    1 倒排索引模型 2 布尔检索类型 3 TF IDF权重计算 下面是TF IDF的JAVA代码实现 public class TFIDF public double tf List
  • vue的循环遍历(v-for)

    1 循环遍历 1 循环遍历 vue的循环遍历用v for 语法类似于js中的for循环 当我们有一组数据需要进行渲染时 我们就可以使用v for来完成 2 v for使用格式 格式为 v for item in items 遍历items中
  • 【Android开发】一文全面解析Framework层

    前言 上一篇文章从Native角度讲解了Android进程管理的相关概念 本文将继续从上层的Framework中的进程启动 销毁场景和优先级处理 以及它们与四大组件的种种关联 来逐步解析Android进程管理的其他关键要素 进程的启动 An
  • 腾讯 Bugly 和 CrashHandler 冲突,不上传日志

    简单介绍 CrashHandler 是继承 UncaughtExceptionHandler 类来处理 app 崩溃 自由度比较大 可以收集日志信息保存到本地 上传网络 并重启应用 可以说是除了三方的异常上报工具 开发者使用最多的一种方式
  • Android Log系统介绍

    前言 日志分析是开发的核心阶段之一 开发人员经常会遇到这样那样的问题 需要借助日志分析来解决 Bug日志有助于在开发阶段识别Android应用中的Bug 一旦应用发布到市场上 开发者 或者支持工程师 也要通过分析bug日志来解决问题 可见
  • EditText横屏键盘全屏的问题

    在EditText的属性 android imeOptions flagNoExtractUi flagNoFullscreen 可以解决问题 一定要设置flagNoFullscreen否则会出现一个切换回竖屏后页面显示不全的问题
  • Citrix_XenDesktop7.5安装图解,实现Citrix虚拟云桌面

    Cirtrix XenDesktop 7 5 安装图解 一 安装 XenDesktop 7 5 安装 Winodws 2012 并加入域 xenad local 计算机名为 xd xenad local 过程略 安装 XenDesktop
  • 【计算机网络09】传输层之TCP连接管理

    文章目录 1 深入理解序号seq 确认号ack 2 建立连接 三次握手 2 1 状态解读 2 2 前 2 次握手的特点 2 3 为什么建立连接要进行 3 次握手 2 次不行吗 2 4 第 3 次握手失败了会怎么处理 3 释放连接 四次挥手
  • 什么是库-适用于当前软件的包

    源头 scrapy学习 scrapy第三方模块 不管官网原理 架构 安装等辅助教程多么花枝招展 最后还是落实到下面第3条说的库的特征 都会体现在lib下的site packages下的scrapy模块里 就是一串串的代码而已 重点 1 内置
  • Python爬虫的scrapy的学习(学习于b站尚硅谷)

    目录 一 scrapy 1 scrapy的安装 1 什么是scrapy 2 scrapy的安装 2 scrapy的基本使用 1 scrap的使用步骤 2 代码的演示 3 scrapy之58同城项目结构和基本方法 注 58同城的数据不是公开数
  • 关于子线程的异常捕获 - UncaughtExceptionHandler

    一 为什么需要Thread UncaughtExceptionHandler 1 主线程可以轻松找到异常 但是子线程不行 子线程异常问题 author xuehw date 2020 03 05 public class Exception
  • go的单元测试介绍

    一 问题引出 在我们工作中 我们会遇到这样的情况 就是去确认一个函数 或者一个模块的结果是否正确 例如 我们会遇到测试下面函数是否正确 func addUpper n int int res 0 for i 1 i lt n i res i
  • 转JSON报错怎么办?增加发生js错误时候的代码强壮性

    在js中有些内置方法在使用的时候当传入意外类型参数的时候会报错卡死导致直接让整个项目都跑不起来了 比如 今天 这里就说一个增加代码强壮性的方法 try catch finally 众所周知 try catch 是处理意外错误时候的语句 主要
  • 《R语言实战》学习笔记:第一章 R语言介绍

    R语言实战 学习笔记 第二章 创建数据集 R语言实战 学习笔记 第三章 图像初阶 R语言实战 学习笔记 第四章 基本数据管理 R语言实战 学习笔记 第五章 高级数据管理 R语言介绍 数值运算 age lt c 1 3 5 2 11 9 3
  • 【Zabbix实战之部署篇】Zabbix的分布式监控部署

    Zabbix实战之部署篇 Zabbix的分布式监控部署 一 Zabbix proxy介绍 1 Zabbix proxy简介 2 Zabbix proxy 使用场景 3 Zabbix的分布式监控拓扑 二 检查本地环境 1 本地环境规划 2 检
  • React中文

    1 Hello World 开始React最简单的方式是在CodePen上使用HelloWorld例子 你不需要安装任何东西 你只要在新的标签页中打开并和我们一起看例子 如果你想要使用一个本地开发环境 可参看Installation页 最小
  • Palindrome Partitioning II

    Calculate and maintain 2 DP states pal i j which is whether s i j forms a pal d i which is the minCut for s i n 1 Once w
  • Java NIO实现WebSocket服务器

    简介 在HTTP请求中 服务器往往处于被动的一方 通常都是客户端向服务器发送请求时 服务器才会做出响应 服务器并不会主动向客户端推送消息 因此WebSocket API就为此诞生 WebSocket API是HTML5中的一大特色 能够使得