In-depth instant messaging development protocol WebSocket protocol details

WebSocket is a new web communication technology in HTML5, which truly realizes full-duplex real-time communication (full-duplex) between the browser and the server. This article will explain the details of the WebSocket communication protocol in detail.

 

The problem of traditional "long polling" to realize instant messaging on the web

Before the emergence of WebSocket, in order to realize instant communication on the Web side, the technology used was Ajax polling. Polling is a specific time interval (such as every 1 second), the browser sends an HTTP request to the server, and then the server returns the latest data to the browser on the client side. This traditional HTTP request mode has obvious disadvantages - the browser needs to continuously send requests to the server, but the header of the HTTP request is very long, and the data contained in it may only be a small value, which will occupy lots of bandwidth.

In the WebSocket API, the browser and the server only need to do a handshake, and then a fast channel is formed between the browser and the server. The two can directly transmit data to each other, changing the original B/S mode.

The request initiated by the websocket on the browser side is generally:

01

02

03

04

05

06

07

08

09

10

11

// javacsript

  var ws = new WebSocket("ws://127.0.0.1:4000");

  ws.onopen = function(){

    console.log("succeed");

  };

  ws.onerror = function(){

    console.log(“error”);

  };

  ws.onmessage = function(e){

  console.log(e);

  }

This request is sent to the port of the server. Generally speaking, a socket will be bound to a port on the server in advance, and the client and the server will communicate on this predetermined port (the one I bind here is port 4000). , by default websocket uses port 80). Instant messaging chat software app development can add Weikeyun's v:weikeyyun24 consultation

 

Then, after the socket on the server side listens to the packet, a new socket is generated, parses the Sec-WebSocket-Key in the sent data, and then adds "Sec-WebSocket-Key" to a magic string according to "Sec-WebSocket-Key" 258EAFA5-E914-47DA-95CA-C5AB0DC85B11”. Use SHA-1 encryption, then BASE-64 encoding, and return the result to the client as the value of the "Sec-WebSocket-Accept" header.

Then the communication will be carried out under this persistent channel, including the query of the browser and the push of the server. The two parties communicate with each other in a full-duplex state.

WebSocket communication protocol

As the above example: the format of the data transmission frame in the switched websocket protocol (the http protocol is no longer used at this time) The instructions given by the official document:

Anyone who looks directly at this will get a bit of a head: I drew a picture to briefly explain the structure of this frame:

Explanation of each field:

1
2
3
4
5
6
7
FIN              1bit 表示信息的最后一帧,flag,也就是标记符
RSV 1-3        1bit each 以后备用的 默认都为 0
Opcode         4bit 帧类型,
Mask              1bit 掩码,是否加密数据,默认必须置为1
Payload len   7bit 数据的长度,当这个7 bit的数据 == 126 时,后面的2 个字节也是表示数     据长度,当它 == 127 时,后面的 8 个字节表示数据长度
Masking-key      1 or 4 bit 掩码
Payload data  playload len  bytes 数据


So our code here uses substr to intercept Masking-key and PlayloadData by judging the value of Playload len.

The way to parse the data according to the mask is:

1
2
3
for ( i = 0 ; i < data.length ; i++){
    orginalData += data[i]  ^  maskingKey[i mod 4 ];
}


In PHP, when we receive the data, we intercept the data according to the format here, and parse it according to the method here to get the data sent by the browser. When we want to send data to the browser, we also assemble the frame according to this format. Here is my method:

01
02
03
04
05
06
07
08
09
10
11
function frame( $s ){
                   $a = str_split ( $s , 125);
                   if ( count ( $a ) == 1){
                           return "\x81" . chr ( strlen ( $a [0])) . $a [0];
                   }
                   $ns = "" ;
                   foreach ( $a as $o ){
                           $ns .= "\x81" . chr ( strlen ( $o )) . $o ;
                   }
                   return $ns ;
           }


强行将要发送的数据分割成 125 Byte / frame,这样 playload len 只需要 7 bits。也就是直接将数据的长度的ASCII 码拼接上去,然后后面跟上要发送的数据。 每一个 frame 前面加的 ‘\x81’ 用二进制就是: 1000 0001 1000 :

1
2
1 是 FIN
000 是三个备用的bit

可以设置 opcode的值,来告诉浏览器这个frame的数据属性。

Guess you like

Origin blog.csdn.net/wecloud1314/article/details/126523264