When WebSocket is communicating, it is possible to choose a transmission mode with string or byte stream. However, when sending and receiving, it is necessary to consider the subcontracting of the data, which is divided into request and response messages. No matter which mode of transmission is used, it is unavoidable to encounter this problem.
When a string is transferred, the receiving side can stitch together each received string, and then detect whether a particular substring appears, such as two consecutive lines, to separate a long string into a single request or response message. This process is relatively simple and effective. But here, another pattern, the transmission of byte streams, is introduced.
First of all, consider the sub-packet problem, generally divided into the message header and the message body. For simple purposes, the message header only holds the length of a message body, which is a byte array.
Determine the packet format next can be realistic modern code, the first is the connection:
varSocket;varUri= "ws://" + window. Location.Host + "/push"; //Example Addressfunction Connect(URI){Socket= New WebSocket(URI); Socket.Binarytype = "Arraybuffer"; Socket.OnOpen = function(e){ Console.Log("connected to server"); }; Socket.OnClose = function(e){ Console.Log("link is closed"); }; Socket.OnMessage = function(e){ doreceive(e.Data); }; Socket.onerror = function(e){ Console.Log("Error occurred"); };}
This defines the socket variable as public, because the subsequent send method will use that variable. The WebSocket transport in the default JavaScript is in string mode, with UTF-8 encoding, by setting the Binarytype property to Arraybuffer to use a byte stream.
When the OnMessage event occurs, the representative receives the data, which is stored in the parameter e.data. Each receive can receive a complete message or part of the message, and we use a doreceive method to split the message packet. The code is as follows:
varReceive=[];varLength= 0;function doreceive(buffer){Receive= Receive.concat(Array. from(New Uint8array(buffer))); if(Receive.length < 4){ return; }Length= New DataView(New Uint8array(receive).Buffer).GetUint32(0); if(Receive.length <Length+ 4){ return; } varbytes= Receive.Slice(4,Length+ 4); dosomething(bytes);Receive= Receive.Slice(length+ 4);};
Where receive is the receive buffer, and each time the data is received, it is stored in the buffer. It then checks if its length is greater than or equal to 4 bytes, which is the length of the message header defined above. If the condition is met, it is read as a Uint32 value, which represents the length of the message body. After checking whether the buffer is greater than the message header and message body length, if satisfied then read the body of the message, then the resulting bytes byte array is the complete message body. Finally, the buffer is reset with the remaining bytes for the next read.
Where the buffer parameter is of type Arraybuffer, which represents the original byte array, itself is meaningless. JavaScript interprets these bytes through a view. Uint8array is one of the views that treats the bytes in Arraybuffer as a 8-bit unsigned integer, exactly one byte corresponding to a uint8 integer. Similarly, Uint16array, which treats bytes in Arraybuffer as a 16-bit unsigned integer, corresponds to one uint16 integer per two bits.
And DataView is a view provided by the JavaScript API, which treats the data in Arraybuffer as a network stream, using a big-endian encoding that can be used to read or write data. Here we use it to read the value of a Uint32.
Next is the Send method, the code is as follows:
function Dosend(bytes){ varBuffer= New ArrayBuffer(bytes.length + 4); varView= New DataView(buffer); View.SetUint32(0, bytes.length); for(varI= 0;I< bytes.length;I++){ View.setUint8(I+ 4,Bytes[i]); } Socket.Send(view);};
Where the parameter bytes is an already encoded byte array, which is stored in the Arraybuffer object by the DataView view for sending. According to the above agreement, you need to set the Uint32 type of message body length, and then set the message body.
Finally, this paper carries out the transmission of the request and response message in the agreed message format, and the message body is an indefinite length sequence of bytes. It is meaningless in itself. We can use the Uint16array, Uint32array and other views provided by the API as a sequence of integer values, or we can self-implement how their content is interpreted.
For example, refer to this as a string using UTF-8 encoding. The string can then be printed or deserialized into a JSON object, and so on.
JavaScript for WebSocket byte stream communication example