Engine.io analysis of the cornerstone of 3--socket.io

Source: Internet
Author: User
Tags emit

Reprint Please specify: Theviper http://www.cnblogs.com/TheViper

The last one tells the execution flow of the first request (handshake), which is how the Engine.io transmits the data after the handshake.

Engine.io binds the request event for HTTP. In the callback function, the handshake request is judged based on whether there is a socket ID.

    if (req._query.sid) {      debug (' setting new request for existing client ');      Self.clients[req._query.sid].transport.onrequest (req);     Else {      Self.handshake (req._query.transport, req);    }

The last one to go is Self.handshake (Req._query.transport, req), and this article goes Self.clients[req._query.sid].transport.onrequest (req);.

The handshake request from the previous article is a GET method. The request to maintain a long connection is also a Get method. When broadcasting, Engine.io receives data, writes data to a long connection, returns a long connection, and then shuts down. If the long connection times out or returns an error, the client will also issue it again. If, within the specified time (pingtimeout, default 60 seconds), the server side does not receive a long connection request from the client, the socket is considered invalid and the socket is purged from clients.

function Socket (ID, server, transport, req) {....    This . Settransport (transport);    This . OnOpen ();}
function () {  varthis;  Cleartimeout (Self.pingtimeouttimer);   = SetTimeout (function  () {    self.onclose (' ping timeout ');   + self.server.pingTimeout);};
Socket.prototype.onOpen =function () {   This. readyState = ' Open '; //sends an ' open ' packet   This. Transport.sid = This. ID;  This. Sendpacket (' Open ', Json.stringify ({sid: This. ID, Upgrades: This. Getavailableupgrades (), PingInterval: This. Server.pinginterval, Pingtimeout: This. server.pingtimeout});  This. Emit (' open ');  This. Setpingtimeout ();};

As you can see, each time a handshake succeeds and a socket is initialized, a timeout timer is set. Timed out the words execute onclose (), inside is a variety of emptying, initialization, and then trigger the Close event, cancel other event bindings and so on.

Back to ONrequest (), different policies are executed for different request methods,

function (req) {  var res = req.res;     if (' GET ' = = Req.method)    {this. Onpollrequest (req, res)  ; Else if (' POST ' = = Req.method)    {this. Ondatarequest (req, res)  ; Else {    Res.writehead (+);    Res.end ();  }};

If it is a Get method

Polling.prototype.onPollRequest =function(req, res) {debug (' Setting request ');  This. req =req;  This. res =Res; varSelf = This; functionOnClose () {Self.onerror (' Poll connection closed prematurely '); }  functionCleanup () {Req.removelistener (' Close ', OnClose); Self.req= Self.res =NULL; } req.cleanup=cleanup; Req.on (' Close ', OnClose);  This. writable =true;  This. Emit (' drain ');};

Onpollrequest () actually does a close event binding, triggering the drain event. The drain event is socket.js inside the this.settransport (transport);

This.transport.on (' Drain ', this.flush.bind (this)); As you can see, the flush () is eventually used.

If this is the Post method

Polling.prototype.onDataRequest =function(req, res) {if( This. Datareq) {    //assert:this.dataRes, '. Datareq and. Datares should be (un) set together '     This. OnError (' data request overlap from client '); Res.writehead (500); return; }  varIsBinary = ' application/octet-stream ' = = = req.headers[' Content-type '];  This. Datareq =req;  This. Datares =Res; varchunks = IsBinary?NewBuffer (0): "; varSelf = This; functionCleanup () {chunks= IsBinary?NewBuffer (0): "; Req.removelistener (' Data ', OnData); Req.removelistener (' End ', onEnd); Req.removelistener (' Close ', OnClose); Self.datareq= Self.datares =NULL; }  functionOnClose () {cleanup (); Self.onerror (' Data request connection closed prematurely '); }  functionOnData (data) {varContentLength; if(typeofdata = = ' String ') {chunks+=data; ContentLength=buffer.bytelength (chunks); } Else{chunks=Buffer.concat ([chunks, data]); ContentLength=chunks.length; }    if(ContentLength >self.maxhttpbuffersize) {chunks= ' ';    Req.connection.destroy (); }  }  functiononEnd () {self.ondata (chunks); varheaders = {      //text/html is required instead of Text/plain to avoid an      //unwanted Download dialog on certain user-agents (GH-43)' Content-type ': ' text/html ',      ' Content-length ': 2    }; //prevent XSS warnings on IE    //https://github.com/LearnBoost/socket.io/pull/1333    varUA = req.headers[' user-agent ']; if(UA && (~ua.indexof ('; MSIE ') | | ~ua.indexof (' trident/')) {headers[' x-xss-protection '] = ' 0 '; } res.writehead (200, Self.headers (req, headers)); Res.end (' OK ');  Cleanup (); } req.abort=cleanup; Req.on (' Close ', OnClose); Req.on (' Data ', OnData); Req.on (' End ', onEnd); if(!isbinary) req.setencoding (' UTF8 '));};

The inside is actually the binding of the event inside the HTTP request. When data is passed in, OnData () determines whether the maximum buffer length is exceeded, and if not exceeded, writes the data to chunks.

When the data is received, OnEnd (). Then Self.ondata (chunks);

 Polling.prototype.onData = function   ' received '%s "'  var  self = this  ;  var  callback = function   (packet) { if  (' Close ' == Packet.type) {      Debug ( ' Got xhr close packet ' );      Self.onclose ();  return  false  ;  }   Self.onpacket (packet);  }; Parser.decodepayload (data, callback);};  

Parser.decodepayload (data, callback), used to handle character encodings, can simply be seen as executing callback functions after data processing.

Self.onpacket (packet); Transport.js inside the parent class.

function (packet) {  this. Emit (' packet ', packet);}; 

Triggers the packet event on the transport, which is also bound in Socket.js's Settransport (). The drain event in the front of Onpollrequest () is also.

Socket.prototype.setTransport =function(transport) { This. Transport =Transport;  This. Transport.once (' Error ', This. Onerror.bind ( This));  This. Transport.on (' packet ', This. Onpacket.bind ( This));  This. Transport.on (' drain ', This. Flush.bind ( This));  This. Transport.once (' Close ', This. Onclose.bind ( This, ' Transport close ')); //This function would manage packet events (also message callbacks)   This. Setupsendcallback ();};

Then the Onpacket () callback

Socket.prototype.onPacket =function(packet) {if(' open ' = = This. ReadyState) {    //Export Packet EventDebug (' Packet ');  This. Emit (' packet ', packet); //Reset Ping Timeout on any packet, incoming data are a good sign of    //Other side ' s liveness     This. Setpingtimeout (); Switch(packet.type) { Case' Ping ': Debug (' Got ping ');  This. Sendpacket (' Pong ');  This. Emit (' Heartbeat ');  Break;  Case' Error ':         This. OnClose (' Parse error ');  Break;  Case' Message ':         This. Emit (' data ', Packet.data);  This. Emit (' message ', Packet.data);  Break; }  } Else{Debug (' Packet received with closed socket '); }};

Reset the timeout timer. Because each time a long connection is closed, a POST request is always issued, Engine.io this determines that the client is still in, at this point, Packet.type is ping, and then returns the heartbeat of the response. The client receives a new get long connection request before it is re-issued.

If the POST request has data, Packet.type will be a message. Triggers the Data,message event. Bindings, callbacks are customized on the server side. This will receive the client's data on the server side.

Finally, Socket.send,socket.write. This is also the way to return data to the client. Very simple.

Socket.prototype.send =function(data, callback) {  this. Sendpacket (' Message ', data, callback);   return  This ;};

Sendpacket () also uses this return handshake response when shaking hands, and this method finally uses flush ().

Engine.io analysis of the cornerstone of 3--socket.io

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.