如何在服务器端发送和接收 WebSocket 消息? [英] How can I send and receive WebSocket messages on the server side?

查看:78
本文介绍了如何在服务器端发送和接收 WebSocket 消息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  • How can I send and receive messages on the server side using WebSocket, as per the protocol?

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

Why do I get seemingly random bytes at the server when I send data from the browser to the server? It the data encoded somehow?

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

How does the framing work in both the server → client and client → server directions?

推荐答案

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

规范 (RFC 6455)

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

(In other words, server → browser)

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

The frames you're sending need to be formatted according to the WebSocket framing format. For sending messages, this format is as follows:

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

文本框架的第一个字节将是 1000 0001(或 129).

The first byte will be 1000 0001 (or 129) for a text frame.

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

The second byte has its first bit set to 0 because we're not encoding the data (encoding from server to client is not mandatory).

需要确定原始数据的长度才能正确发送长度字节:

It is necessary to determine the length of the raw data so as to send the length bytes correctly:

  • 如果 0 <= length <= 125,则不需要额外的字节
  • 如果126 <= length <= 65535,则需要另外两个字节,第二个字节是126
  • 如果length >= 65536,则需要额外8个字节,第二个字节是127
  • if 0 <= length <= 125, you don't need additional bytes
  • if 126 <= length <= 65535, you need two additional bytes and the second byte is 126
  • if length >= 65536, you need eight additional bytes, and the second byte is 127

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

The length has to be sliced into separate bytes, which means you'll need to bit-shift to the right (with an amount of eight bits), and then only retain the last eight bits by doing AND 1111 1111 (which is 255).

在长度字节之后是原始数据.

After the length byte(s) comes the raw data.

这导致以下伪代码:

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)


接收消息

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


Receiving messages

(In other words, browser → server)

您获取的帧格式如下:

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

第一个字节通常无关紧要 - 如果您只是发送文本,则仅使用文本类型.在这种情况下,它将是 1000 0001(或 129).

The first byte usually does not matter - if you're just sending text you are only using the text type. It will be 1000 0001 (or 129) in that case.

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

The second byte and the additional two or eight bytes need some parsing, because you need to know how many bytes are used for the length (you need to know where the real data starts). The length itself is usually not necessary since you have the data already.

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

The first bit of the second byte is always 1 which means the data is masked (= encoded). Messages from the client to the server are always masked. You need to remove that first bit by doing secondByte AND 0111 1111. There are two cases in which the resulting byte does not represent the length because it did not fit in the second byte:

  • 0111 1110的第二个字节,或126,表示后面两个字节用于长度
  • 0111 1111的第二个字节,或127,表示后面的8个字节用于长度
  • a second byte of 0111 1110, or 126, means the following two bytes are used for the length
  • a second byte of 0111 1111, or 127, means the following eight bytes are used for the length

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

The four mask bytes are used for decoding the actual data that has been sent. The algorithm for decoding is as follows:

decodedByte = encodedByte XOR masks[encodedByteIndex MOD 4]

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

where encodedByte is the original byte in the data, encodedByteIndex is the index (offset) of the byte counting from the first byte of the real data, which has index 0. masks is an array containing of the four mask bytes.

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

This leads to the following pseudocode for decoding:

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

这篇关于如何在服务器端发送和接收 WebSocket 消息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆