如何在服务器端发送和接收 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 消息? 的相关文章

  • UTF8/UTF16 和 Base64 在编码方面有什么区别

    In c 我们可以使用下面的类来进行编码 System Text Encoding UTF8 System Text Encoding UTF16 System Text Encoding ASCII 为什么没有System Text En
  • Java Swing 的 UTF-8 支持问题? [复制]

    这个问题在这里已经有答案了 可能的重复 如何在Swing应用程序中实现UTF 8格式 https stackoverflow com questions 13804113 how to implement utf 8 format in s
  • 流媒体性能 - Canvas 与

    我正在开发一个应用程序 需要通过 webSocket 连接以每秒至少 30 帧的速度持续传输图像 我遇到了一些性能问题 并希望尽我所能进行优化 我想知道使用不断更新的图像之间的性能差异是什么 就像这样 img src someDynamic
  • 在龙卷风 v4+ 下,WebSocket 连接被拒绝并显示 403

    我有一个旧的龙卷风服务器 可以处理普通的 WebSocket 连接 我通过 Nginx 将这些连接从 wss info mydomain com 代理到 wss mydomain com 8080 以便绕过阻止非标准端口的客户代理 最近升级
  • 如何检测字符串字节编码?

    我读取了大约 1000 个文件名os listdir 有些是UTF8编码 有些是CP1252 我想将它们全部解码为 Unicode 以便在我的脚本中进一步处理 有没有办法让源编码正确解码为 Unicode Example for item
  • 使用正则表达式验证字符串是否安全

    我有一个网站 用户可以在其中选择用户名 目前 他们可以输入几乎任何字符 包括 ETC 我知道我可以使用正则表达式 这可能就是我的选择 我将使用否定集 我认为这是正确的工具 如下所示 那么 我怎样才能知道要放入该集合中的所有非法字符呢 我可以
  • 代理阻止网络套接字?如何绕行

    我有一个用 Python 编写的正在运行的 websocket 服务器 来自https github com opiate SimpleWebSocketServer https github com opiate SimpleWebSoc
  • IP 地址 v4/v6 等效性测试

    是否可以在使用 IPv4 和 IPv6 的双栈环境中测试 IP 地址的等效性 如果是这样 怎么办 我的应用程序使用网络套接字 https github com zaphoyd websocketpp在 Boost ASIO 之上 举个例子
  • 如何更改 TextWriter 对象中的编码?

    我有 xml 是通过 API 在另一个 resurse 中发送的 我通过 XDocument 创建它 XDocument xDoc new XDocument new XDeclaration 1 0 utf 8 yes new XElem
  • Rails 3、mysql/mysql2 将某些检索到的字符串误解为 ASCII-8BIT

    这个问题最初是常见的 字符编码不兼容 ASCII 8BIT 和 UTF 8 问题 但事实是not我在问什么 相反 我发现发生此问题是因为数据库的某些字段在检索时被标记为 ASCII 8BIT 而大多数字段正确显示为 UTF 8 例如 在包含
  • 为什么 Python 不能打印 Unicode 符号? [复制]

    这个问题在这里已经有答案了 可能的重复 Python UnicodeDecodeError 我是否误解了编码 https stackoverflow com questions 368805 python unicodedecodeerro
  • 替换非 UTF8 字符

    在 php 中 我需要替换字符串中的所有非 UTF8 字符 然而 并不是通过某种等价物 比如iconv功能与 TRANSLIT 但是由一些选定的角色 例如 or 例如 通常 我希望用户能够看到找到无效字符的位置 我没有找到任何执行此操作的函
  • Swift:覆盖子类内的类型别名

    所以我正在考虑在我的项目中使用自定义模式 但我无法让它发挥作用 主要思想是改变typealias在每个子类上访问子类特定的接口 protocol InstanceInterface class typealias Interface var
  • 从 Process.StandardOutput 重定向二进制数据会导致数据损坏

    On top of this https stackoverflow com questions 8978390 passing command line arguments from c sharp to a external exe 8
  • 返回 Self 的协议函数

    我有一个返回对象副本的协议 P protocol P func copy gt Self 和一个实现 P 的 C 类 class C P func copy gt Self return C 但是 我是否将返回值设置为Self我收到以下错误
  • 如何将大文件 (>1 GB) 的编码转换为 Windows 1252,而不出现内存不足异常?

    考虑 public static void ConvertFileToUnicode1252 string filePath Encoding srcEncoding try StreamReader fileStream new Stre
  • 为什么 websocket 需要使用 HTTP 进行打开握手?为什么不能成为一个独立的协议呢?

    Websocket 的设计方式是 通过使其握手成为有效的 HTTP 升级请求 其服务器可以与 HTTP 服务器共享端口 我对这个设计理念存有疑问 无论如何 WebSocket 协议都是一个独立的基于 TCP 的协议 为什么我们需要这个 HT
  • 检查 WebRTC 连接 - 可靠的方法

    我有一个实时视频聊天应用程序 并且使用支持 STUN TURN 和 UPD TCP 传输的 TURN 服务器 有时用户可以连接到网络blocksWebRTC 连接的端口和协议就这么多不可能发生 通常这些是公司网络 我想在用户尝试相互连接之前
  • 同域策略如何应用于 Firefox 和 Chrome 扩展程序中的后台脚本(非内容脚本)?

    据我了解 扩展中有两种类型的脚本 一种是从网页中的 DOM 运行并与之交互的 内容脚本 它们受同源策略的约束 另一种是 内容脚本 其他的是脚本 调用它们 扩展脚本 在后台运行 可能会也可能不会与网页交互 例如main js在火狐或背景 js
  • R 中的 Websocket

    我设法在 R 中建立到 Mtgox websocket 的连接 规格如下 url https socketio mtgox com mtgox Currency USD https socketio mtgox com mtgox Curr

随机推荐