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

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

问题描述


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


  • 当我将数据从浏览器发送到服务器时,为什么会在服务器上看到随机字节?数据是否以某种方式编码?


  • 框架在服务器和rarr之间如何工作?客户端和客户端服务器方向?



解决方案

伪代码关于如何实现一个非常简单的服务器,可以根据确定的框架格式处理传入和传出的WebSocket消息。它不包括握手过程。此外,这个答案是为了教育目的而作出的;它不是全功能的实现。



规范(RFC 6455)






发送邮件



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



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




  • 包含数据类型的一个字节(以及一些超出范围的附加信息)对于一个平凡的服务器)

  • 一个字节,其长度

  • 如果长度不适合第二个字节(两第二个字节是一个代码,说明长度使用了多少个字节)

  • 实际(原始)数据



文本框架的第一个字节将为 1000 0001 (或 129 )。 p>

第二个字节的第一个位设置为 0 ,因为我们不对数据进行编码(从服务器到客户端的编码不需要)



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




  • 如果 0 <= length <= 125 ,则不需要额外的字节

  • 如果 126< = length< = 65535 ,y ou需要两个额外的字节,第二个字节是 126

  • 如果 length> = 65536 ,你需要八个额外的字节,第二个字节是 127



长度必须被分成不同的字节,这意味着你需要向右移位(8位),然后只通过执行 AND 1111 1111 (这是 255 )。



长度字节s / b

这将导致以下伪代码: $ c> bytesFormatted [0] = 129

indexStartRawData = -1 //无论什么值是
//设置在这里 - 它将立即设置:

如果bytesRaw.length< = 125
bytesFormatted [1] = bytesRaw.length

indexStartRawData = 2

如果bytesRaw.length> = 126和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

//将原始数据放在正确的索引
bytesFormatted.put(bytesRaw ,indexStartRawData)


//现在发送字节格式(例如写入套接字流)






接收邮件



(换句话说,浏览器和rarr;服务器)



您获取的框架采用以下格式:




  • 一包含数据类型的字节

  • 一个字节,包含长度

  • 如果长度不符合第二个字符,则为两个或八个附加字节字节

  • 四个字节为掩码(=解码密钥)

  • 实际数据



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



第二个字节和另外两个或八个字节需要一些解析,因为您需要知道使用多少个字节的长度(您需要知道实际数据的开始位置)。长度本身通常不是必需的,因为您已经有数据。



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




  • 第二个字节 0111 1110 126 表示以下两个字节用于长度

  • 第二个字节 0111 1111 127 表示以下八个字节用于长度



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

  decodingByte = encodedByte XOR掩码[encodedByteIndex MOD 4] 

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



这导致以下伪代码进行解码:

  secondByte = bytes [1] 

length = secondByte AND 127 //可能不是两个特殊情况下的实际长度

indexFirstMask = 2 //如果不是特殊情况

如果长度== 126 //如果一个特殊情况,更改indexFirstMask
indexFirstMask = 4

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

mask = bytes.slice(indexFirstMask,4)//从indexFirstMask开始的四个字节

indexFirstDataByte = indexFirstMask + 4 //另外四个字节

decoded = new array

decoded.length = bytes.length - indexFirstDataByte //实数数据的长度

for i = indexFirstDataByte,j = 0; i< bytes.length; i ++,j ++
decoding [j] = bytes [i] XOR掩码[j MOD 4]


//现在使用decode解释接收到的数据


  • 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?

解决方案

Note: This is some explanation and pseudocode as to how to implement a very trivial server that can handle incoming and outcoming WebSocket messages as per the definitive framing format. It does not include the handshaking process. Furthermore, this answer has been made for educational purposes; it is not a full-featured implementation.

Specification (RFC 6455)


Sending messages

(In other words, server → browser)

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

  • one byte which contains the type of data (and some additional info which is out of scope for a trivial server)
  • one byte which contains the length
  • either two or eight bytes if the length does not fit in the second byte (the second byte is then a code saying how many bytes are used for the length)
  • the actual (raw) data

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

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:

  • 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

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.

This leads to the following pseudocode:

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)

The frames you obtain are in the following format:

  • one byte which contains the type of data
  • one byte which contains the length
  • either two or eight additional bytes if the length did not fit in the second byte
  • four bytes which are the masks (= decoding keys)
  • the actual data

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.

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:

  • 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]

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天全站免登陆