Detail WebSocket--node. JS Chapter

Source: Internet
Author: User
Tags rfc sha1

In the previous article, there were various ways to improve web communication, including polling, long connections, and the means mentioned in various HTML5. This article will describe in detail the implementation of the WebSocket protocol in Web communication.

One, WebSocket Agreement 1. Overview

The WebSocket protocol allows untrusted client code to control remote hosts in a controlled network environment. The protocol consists of a handshake and a basic message frame, layered over TCP. To put it simply, a secure information pipeline was created after the handshake was answered, which was significantly better than the XMLHttpRequest-based IFRAME data stream and long polling described earlier. The protocol consists of two aspects, the grip bracelet (handshake) and the data transfer (data transfer).

2. Handshake Connection

This part is relatively simple, like meeting acquaintances on the road hello.

Client: Hey, Big Brother, is there a fire? (Smoke handed over) Server: Ha, yes, come on (dot) Client: Matches ah, also OK! (On the smoke point, verification completed)

Handshake connection, the client first actively hand:

Get/chat Http/1.1host:server.example.comupgrade:websocketconnection:upgradesec-websocket-key: Dghlihnhbxbszsbub25jzq==origin:http://example.comsec-websocket-protocol:chat, Superchatsec-websocket-version:13

The client sends a string of BASE64 encryption keys in the past, which is the sec-websocket-key you see above. After the Server sees the client greeting, he whispers to the client that he already knows and says hello.

http/1.1 101 Switching protocolsupgrade:websocketconnection:upgradesec-websocket-accept:s3pplmbitxaq9kygzzhzrbk+ Xoo=sec-websocket-protocol:chat

The Server returns the sec-websocket-accept response, which is generated in a certain way. The build algorithm is:

Mask  = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";  This is the fixed string to be used in the algorithm accept = base64 (SHA1 (key + mask));

After the key and mask are SHA-1 processed, the processed data is Base64 encrypted once again. Decomposition action:

1. T = "ghlihnhbxbszsbub25jzq==" + "258eafa5-e914-47da-95ca-c5ab0dc85b11", "   ghlihnhbxbszsbub25jzq==" 258eafa5-e914-47da-95ca-c5ab0dc85b11 "2. s = SHA1 (t),    0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6       0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0 Xea3. Base64 (s),    "s3pplmbitxaq9kygzzhzrbk+xoo="

The HTTP status code returned on the Server side of the above is 101, if not 101, that means the handshake failed at first.

Here is a demo, with the server to shake a hand:

var crypto = require (' crypto '); require (' net '). Createserver (function(o) {     var key;    O.on (' data ',function(e) {        if(!  Key) {            //  handshake            //  answer section, the code first omits             Console.log ( E.tostring ());        } Else {        };    });}). Listen (8000);

Client code:

var ws=New WebSocket ("ws://127.0.0.1:8000"); Ws.onerror=function(e) {  Console.log (e);};

The above is of course a string of incomplete code, the purpose is to demonstrate the handshake process, the client to the server to greet. In the console we can see:

It looks familiar, actually sending an HTTP request, which we can also see in the browser's Network:

But the WebSocket protocol is not the HTTP protocol, just beginning to verify the use of the HTTP header, the communication after the successful connection is not HTTP, do not believe that you use the Fiddler2 grab bag to try, it is certainly not available, the latter part of the communication is TCP-based connection.

To successfully communicate, the server must have an answer and look down:

//Server ProgramsvarCrypto = require (' crypto '));varWS = ' 258eafa5-e914-47da-95ca-c5ab0dc85b11 '; require (' Net '). Createserver (function(o) {varkey; O.on (' Data ',function(e) {if(!key) {            //HandshakeKey = E.tostring (). Match (/sec-websocket-key: (. +)/) [1]; Key= Crypto.createhash (' SHA1 '). Update (key + WS). Digest (' base64 '); O.write (' http/1.1 101 Switching protocols\r\n '); O.write (' Upgrade:websocket\r\n '); O.write (' Connection:upgrade\r\n '); O.write (' sec-websocket-accept: ' + key + ' \ r \ n '); O.write (' \ r \ n '); }Else{Console.log (e);    }; });}). Listen (8000);

About the crypto module, you can look at the official document, the above code should be well understood, after the server answer, the Client to get sec-websocket-accept, and then do a local validation, if the validation passed, it will trigger the OnOpen function.

// Client Programs var ws=New WebSocket ("Ws://127.0.0.1:8000/"); Ws.onopen=function(e) {    Console.log ("handshake success");};

Can see

3. Data frame format

An official document provides a structure diagram

  0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-------+-+-------------+-------------------------------+ | F| r| r| r| opcode| m|    Payload Len | Extended Payload Length | | i| s| s|  s| (4) |     a|             (7) | (16/64) | | n| v| v|       v| |             s|   |       (if payload len==126/127) | | |1|2|3| |             k|                               | |     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + | Extended payload length continued, if payload len = = 127 |                               + - - - - - - - - - - - - - - - +-------------------------------+ | | Masking-key, if MASK set to 1 | +-------------------------------+-------------------------------+ |          Masking-key (continued) | Payload Data |                +-----------------------------------------------+: Payload Data continued ... : + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | Payload Data Continued ... | +---------------------------------------------------------------+

First glance at this picture I am afraid to vomit blood, if the university to modify the computer network This course should not be unfamiliar with this thing, data transfer Protocol, it is necessary to define the length of bytes and related meanings.

FIN      1bit represents the last frame of information, flag, that is, the marker RSV 1-3  1bit each after the default is 0Opcode   4bit frame type, later in detail mask     1bit mask, whether to encrypt data, The default must be set to 1 (It hurts here) Payload  7bit Data length Masking-key      1 or 4 bit mask Payload data     (x + y) bytes extension   TES  Extended Data Application database y bytes  program data

Each frame of the transmission is to comply with this protocol rules, know this protocol, then the resolution is not too difficult, below I took the next time the code of cobalt carbonate classmate.

4. Parsing and encoding of data frames

Parsing code for data frames:

functionDecodedataframe (e) {varI=0,j,s,frame={    //parsing the first two bytes of basic dataFin:e[i]>>7,opcode:e[i++]&15,mask:e[i]>>7, Payloadlength:e[i++]&0x7f  }; //Handling Special Lengths 126 and 127  if(frame. payloadlength==126) Frame.length= (e[i++]<<8) +e[i++]; if(frame. payloadlength==127) I+=4,//The length is typically four-byte integers, the first four bytes are usually left blank for long shapingFrame.length= (e[i++]<<24) + (e[i++]<<16) + (e[i++]<<8) +e[i++]; //determine whether to use masks  if(frame. Mask) {//Get Mask EntityFrame. maskingkey=[e[i++],e[i++],e[i++],e[i++]]; //make a different or operation of data and masks     for(J=0,s=[];j<frame. payloadlength;j++) S.push (e[i+j]^frame. Maskingkey[j%4]); }ElseS=e.slice (I,frame. Payloadlength);//Otherwise, use the data directly  //arrays into buffers to uses=NewBuffer (s); //if necessary, convert the buffer to a string to use  if(frame. Opcode==1) s=s.tostring (); //set up the data sectionFrame. Payloaddata=s; //Return Data Frame  returnframe;}

Encoding of the data frame:

//NodeJSfunctionEncodedataframe (e) {vars=[],o=NewBuffer (e.payloaddata), l=o.length; //Enter first byteS.push ((e.fin<<7) +E.opcode); //Enter the second byte, determine its length, and put it in the corresponding subsequent length message  //Never use masks  if(l<126) S.push (L); Else if(l<0x10000) S.push (126, (L&AMP;0XFF00) >>2,l&0xff); ElseS.push (127, 0,0,0,0,//8 bytes of data, the first 4 bytes are generally useless empty(l&0xff000000) >>6, (l&0xff0000) >>4, (l&0xff00) >>2,l&0xff  ); //returns the merge buffer of the header and data parts  returnBuffer.concat ([NewBuffer (s), O]);}

Some children's shoes may not understand what data should be parsed. This parsing task is mainly server-side processing, the client sends the past data is binary stream form, for example:

var New WebSocket ("Ws://127.0.0.1:8000/"function() {ws.send ("handshake succeeded");};

The information that the Server receives is this:

A binary stream that is placed in buffer format. And when we output it, we parse the binary stream:

//Server ProgramsvarCrypto = require (' crypto '));varWS = ' 258eafa5-e914-47da-95ca-c5ab0dc85b11 '; require (' Net '). Createserver (function(o) {varkey; O.on (' Data ',function(e) {if(!key) {            //HandshakeKey = E.tostring (). Match (/sec-websocket-key: (. +)/) [1]; Key= Crypto.createhash (' SHA1 '). Update (key + WS). Digest (' base64 '); O.write (' http/1.1 101 Switching protocols\r\n '); O.write (' Upgrade:websocket\r\n '); O.write (' Connection:upgrade\r\n '); O.write (' sec-websocket-accept: ' + key + ' \ r \ n '); O.write (' \ r \ n '); }Else{            //parse frame before outputConsole.log (Decodedataframe (e));    }; });}). Listen (8000);

The output is an object with very clear frame information:

5. Control of the connection

Above I bought a xiaoguanzi, mentioned opcode, not detailed, official documents also gave a table:

| Opcode  | Meaning                             | Reference |-+--------+-------------------------------------+-----------| | 0      | Continuation Frame                  | RFC 6455  |-+--------+-------------------------------------+-----------| | 1      | Text Frame                          | RFC 6455  |-+--------+-------------------------------------+-----------| | 2      | Binary Frame                        | RFC 6455  |-+--------+-------------------------------------+-----------| | 8      | Connection Close Frame              | RFC 6455  |-+--------+-------------------------------------+-----------| | 9      | Ping Frame                          | RFC 6455  |-+--------+-------------------------------------+-----------| | |     Pong Frame                          | RFC 6455  |-+--------+-------------------------------------+-----------|

Decodedataframe parse the data, the resulting data format is:

{    fin:1,    opcode:1,    mask:1,    payloadlength:4,    maskingkey: [159, +, 207,],    payloaddata: ' Grip Hand Success '}

Then you can view the above, the role of this frame is to send text, as a text frame. Because the connection is TCP-based, directly shut down the TCP connection, the channel is closed, but WebSocket design is also more humane, close before you say hello, on the server side, you can judge the opcode frame:

var frame=Decodedataframe (e); Console.log (frame); if (frame. Opcode==8) {    // disconnect }

The data (frame) format of the client-server interaction is the same, and as long as the client sends it ws.close() , it performs the action above. Conversely, if the server sends the same close frame to the client (Close frame):

O.write (Encodedataframe ({    fin:1,    opcode:8,    payloaddata:buf}));

The client will be OnClose function, so the interaction is also a rule of the moment, not prone to error.

Ii. precautions 1. WebSocket URIs

Many people may only know ws://text.com:8888 , but in fact the WebSocket protocol address can be added with path and query.

Ws-uri = "WS:" "//" host [":" Port] path ["?" Query]wss-uri = "WSS:" "//" host [":" Port] path ["?" query]

If you are using the WSS protocol, the URI will be connected in a secure manner. The WSS case is not sensitive here.

2. "Superfluous" part of the Agreement (Spit Groove)

The handshake request contains the Sec-websocket-key field, discerning eye can be seen as a WebSocket connection, and this field of encryption in the server is also fixed, if others want to black you, not too difficult.

And then the Maskingkey mask, since the mandatory encryption (mask is 1 for encryption, encryption is the Maskingkey and payloaddata to be different or processing), but also need to let developers deal with this thing? Just encapsulate it inside, right?

3. Relationship to TCP and HTTP

The WebSocket protocol is a TCP-based protocol that is associated with HTTP when the handshake is linked (an HTTP request is made), and the request is switched to the (Upgrade) websocket protocol by the server. The WebSocket uses port 80 as the default WebSocket connection port, while WebSocket is running 443 ports.

Iii. references
    • http://tools.ietf.org/html/rfc6455 Web standard-the WebSocket Protocol
    • Http://www.w3.org/TR/websockets/W3.ORG-WebSockets

Turn http://www.cnblogs.com/hustskyking/p/websocket-with-node.html

Detail WebSocket--node. JS Chapter

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.