如何在服务器端发送和接收 WebSocket 消息?

2023-12-29

  • 如何根据协议使用 WebSocket 在服务器端发送和接收消息?

  • 当我从浏览器向服务器发送数据时,为什么我在服务器上得到看似随机的字节?它是以某种方式编码的数据吗?

  • 成帧如何在服务器→客户端和客户端→服务器方向上工作?


注意:这是一些关于如何实现一个非常简单的服务器的解释和伪代码,该服务器可以根据最终的帧格式处理传入和传出的 WebSocket 消息。它不包括握手过程。此外,这个答案是出于教育目的;它不是一个功能齐全的实现。

规范(RFC 6455) https://www.rfc-editor.org/rfc/rfc6455


发送消息

(换句话说,服务器→浏览器)

您发送的帧需要根据 WebSocket 帧格式进行格式化。对于发送消息,该格式如下:

  • 包含数据类型的一个字节(以及一些超出普通服务器范围的附加信息)
  • 包含长度的一个字节
  • 如果长度不适合第二个字节,则为两个或八个字节(第二个字节是一个代码,说明长度使用了多少字节)
  • 实际(原始)数据

第一个字节将是1000 0001 (or 129)用于文本框架。

第二个字节的第一位设置为0因为我们没有对数据进行编码(从服务器到客户端的编码不是强制性的)。

需要确定原始数据的长度,以便正确发送长度字节:

  • if 0 <= length <= 125,你不需要额外的字节
  • if 126 <= length <= 65535,您需要两个额外的字节,第二个字节是126
  • if length >= 65536,您需要八个额外字节,第二个字节是127

长度必须被分割成单独的字节,这意味着您需要向右位移(八位),然后只保留最后八位AND 1111 1111(这是255).

长度字节之后是原始数据。

这导致以下伪代码:

bytesFormatted[0] = 129

indexStartRawData = -1 // it doesn't matter what value is
                       // set here - it will be set now:

if bytesRaw.length <= 125
    bytesFormatted[1] = bytesRaw.length

    indexStartRawData = 2

else if bytesRaw.length >= 126 and bytesRaw.length <= 65535
    bytesFormatted[1] = 126
    bytesFormatted[2] = ( bytesRaw.length >> 8 ) AND 255
    bytesFormatted[3] = ( bytesRaw.length      ) AND 255

    indexStartRawData = 4

else
    bytesFormatted[1] = 127
    bytesFormatted[2] = ( bytesRaw.length >> 56 ) AND 255
    bytesFormatted[3] = ( bytesRaw.length >> 48 ) AND 255
    bytesFormatted[4] = ( bytesRaw.length >> 40 ) AND 255
    bytesFormatted[5] = ( bytesRaw.length >> 32 ) AND 255
    bytesFormatted[6] = ( bytesRaw.length >> 24 ) AND 255
    bytesFormatted[7] = ( bytesRaw.length >> 16 ) AND 255
    bytesFormatted[8] = ( bytesRaw.length >>  8 ) AND 255
    bytesFormatted[9] = ( bytesRaw.length       ) AND 255

    indexStartRawData = 10

// put raw data at the correct index
bytesFormatted.put(bytesRaw, indexStartRawData)


// now send bytesFormatted (e.g. write it to the socket stream)

接收消息

(换句话说,浏览器→服务器)

您获得的帧采用以下格式:

  • 包含数据类型的一个字节
  • 包含长度的一个字节
  • 如果长度不适合第二个字节,则附加两个或八个字节
  • 四个字节是掩码(=解码密钥)
  • 实际数据

第一个字节通常并不重要 - 如果您只是发送文本,那么您只使用文本类型。这将是1000 0001 (or 129) 在这种情况下。

第二个字节和附加的两个或八个字节需要进行一些解析,因为您需要知道长度使用了多少字节(您需要知道真正的数据从哪里开始)。长度本身通常不是必需的,因为您已经拥有数据。

第二个字节的第一位始终是1这意味着数据被屏蔽(=编码)。从客户端到服务器的消息始终被屏蔽。您需要通过执行以下操作来删除第一位secondByte AND 0111 1111。有两种情况,结果字节不代表长度,因为它不适合第二个字节:

  • 第二个字节0111 1110, or 126,表示后面两个字节用于长度
  • 第二个字节0111 1111, or 127,表示后面的八个字节用于长度

四个掩码字节用于解码已发送的实际数据。解码算法如下:

decodedByte = encodedByte XOR masks[encodedByteIndex MOD 4]

where encodedByte是数据中的原始字节,encodedByteIndex是从第一个字节开始计数的字节索引(偏移量)真实数据的,其中有索引0. masks是包含四个掩码字节的数组。

这导致了以下用于解码的伪代码:

secondByte = bytes[1]

length = secondByte AND 127 // may not be the actual length in the two special cases

indexFirstMask = 2          // if not a special case

if length == 126            // if a special case, change indexFirstMask
    indexFirstMask = 4

else if length == 127       // ditto
    indexFirstMask = 10

masks = bytes.slice(indexFirstMask, 4) // four bytes starting from indexFirstMask

indexFirstDataByte = indexFirstMask + 4 // four bytes further

decoded = new array

decoded.length = bytes.length - indexFirstDataByte // length of real data

for i = indexFirstDataByte, j = 0; i < bytes.length; i++, j++
    decoded[j] = bytes[i] XOR masks[j MOD 4]


// now use "decoded" to interpret the received data
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在服务器端发送和接收 WebSocket 消息? 的相关文章

  • Python - Unicode 到 ASCII 的转换

    我无法在不丢失数据的情况下将以下 Unicode 转换为 ASCII u ABRA xc3O JOS xc9 I tried encode and decode他们不会这么做 有人有建议吗 Unicode 字符u xce0 and u xc
  • webhook 和 websocket 之间的区别?

    我一直想进行实时聊天 几年前我用 PHP Ajax Mysql 完成了这个任务 并破坏了我的服务器 然后我尝试使用 Flash 文本文件 我放弃了 10年没有尝试过 但最近我听说了 webhooks 和 websockets 它们似乎都是做
  • Dispatcher-servlet 无法映射到 websocket 请求

    我正在开发一个以Spring为主要框架的Java web应用程序 特别使用Spring core Spring mvc Spring security Spring data Spring websocket 像这样在 Spring 上下文
  • 如何将中间件绑定到socket.io中的事件

    现在您可以将中间件绑定到io use middleware 但这仅在建立套接字连接时触发 有没有办法在将其传递给事件句柄之前拦截它 就像在expressjs中一样 换句话说 In 快递 js你可以做 app get middleware1
  • 快速重写函数错误

    我有一个结构 struct ErrorResultType ErrorType var description String var code Int 和一个协议 protocol XProtocol func dealError erro
  • crypto createHMAC 输出根据 Nodejs 版本而有所不同

    我在升级节点版本时遇到加密模块问题 创建的HMAC取决于节点的版本 您将在下面找到重现该问题的代码片段 如果我将密钥编码为 BASE64 或任何 HMAC 不依赖于 node js 版本 如果我将其编码为二进制 则当我更改 Node js
  • http://localhost:8080 未重定向到 opensso 登录页面

    我的 Liferay Tomcat 服务器在端口 8080 上运行 当我尝试通过输入 url 从服务器访问应用程序时http localhost 8080 它没有重定向到登录页面 而是给我错误 The Connection to abc x
  • 表单帖子上的 asp.net mvc 编码

    我在我的 asp net mvc 表单 带有文本区域的 nicedit 中使用富文本编辑器 当我在帖子上提交表单时 因为它不是 html 编码的 我收到以下消息 从客户端检测到潜在危险的 Request Form 值 如何对 post 上的
  • .NET:如何判断编码是否支持字符串中的所有字符?

    我需要输出大量文本 其中包括多种语言的各种字符 有时我需要以 Unicode 以外的字符编码 例如 Shift JIS 或 ISO 8859 2 输出文本 以便匹配它要访问的页面 如果文本中包含编码无法处理的字符 例如 ISO 8859 2
  • Swift 中符合协议的泛型类型

    是否可以要求泛型类型的特定实例符合 Swift 中的协议 例如 假设我有一个名为的泛型类型Thing
  • pyodbc 无法正确处理 unicode 数据

    我确实使用 pyodbc 成功连接了 MySQL 数据库 并且它可以很好地处理 ascii 编码的数据 但是当我打印使用 unicode utf8 编码的数据时 它引发了错误 UnicodeEncodeError ascii codec c
  • 消息队列与套接字

    我没有太多的套接字编程经验 但我尝试阅读一些相关内容 我对 MDB 和消息队列非常熟悉 有人告诉我队列 例如 MDB 只不过是直接套接字连接 有人可以帮我比较一下这两个吗 两者是无与伦比的 因为它们代表不同的layers 这就像将关系数据库
  • Json.dump 失败并显示“必须是 unicode,而不是 str”TypeError

    我有一个 json 文件 其中恰好有大量中文和日文 以及其他语言 字符 我将其加载到我的 python 2 7 脚本中使用io open如下 with io open multiIdName json encoding utf 8 as j
  • 将 .parquet 编码为 io.Bytes

    目标 将 Parquet 文件上传到 MinIO 这需要将文件转换为字节 我已经能够做到这一点了 csv json and txt bytes data to csv encode utf 8 bytes json dumps self d
  • Golang 结构的 XML 和 JSON 标签?

    我有一个可以根据 HTTP 请求标头输出为 JSON 或 XML 的应用程序 我可以通过将正确的标签添加到我正在使用的结构中来实现正确的输出 但我不知道如何为 JSON 和 XML 指定标签 例如 序列化以纠正 XML type Foo s
  • 流媒体性能 - Canvas 与

    我正在开发一个应用程序 需要通过 webSocket 连接以每秒至少 30 帧的速度持续传输图像 我遇到了一些性能问题 并希望尽我所能进行优化 我想知道使用不断更新的图像之间的性能差异是什么 就像这样 img src someDynamic
  • PHP Imagick - setTextEncoding() 函数不起作用

    我正在尝试在 Imagick 对象上添加一些文本 但是我使用 setTextEncoding 函数 它仍然不起作用 draw new ImagickDraw draw gt setTextEncoding utf 8 draw gt set
  • Tornado websocket handler , self.close() 正在关闭连接而不触发 on_close() 方法

    我是 python stackoverflow tornado 的新手 所以请耐心等待 纠正我 我正在使用龙卷风开发实时应用程序 当我在 Websocket 处理程序类中调用 self close 时 on close 方法不会启动 这次我
  • Swift 中的协议与多态性

    我对面向对象编程相当陌生 我正在尝试了解协议 委托和多态性 我最近观看了一个培训视频 其中宣传当您有两个相似且具有相似方法实现的类时 协议是优雅地实现此目的的最佳解决方案 这就说得通了 然而 一些额外的研究让我发现了多态性 听起来这也是一种
  • 使用 JSON 传递 HTML

    我正在使用 JSON 将数据传递到 iPhone 和 iPad 数据的一个字段是 HTML 问题是编码 这是我得到的回复 gt GadgetHTML strong Hello strong gt from Catworld br n img

随机推荐