The distribution of Message Centers is achieved through establishing a persistent connection between websocket and the backend server. The advantage of this method is to save network bandwidth, second, users can receive messages sent from the backend in real time. netty is used in the backend implementation. After stress testing, each server can withstand 0.5 million persistent connections, that is, 0.5 million users at the same time (only one persistent connection is established for each website user), and the performance is better.
To establish a persistent connection, the client needs to initiate a handshake with the server. The following is an example from Wikipedia:
Browser request:
GET/demo HTTP/1.1 HOST: Example. comconnection: UpgradeSec-WebSocket-Key2: 12998 5 Y3 1. p00Sec-WebSocket-Protocol: sampleupgrade: WebSocketSec-WebSocket-Key1: 4 @ 1 46546xw % 0l 1 5 origin: http://example.com ^ N: DS [4u
In the request, the "Sec-WebSocket-Key1", "Sec-WebSocket-Key2" and the last "^ N: DS [4u" are random, and the server uses the data to construct a 16-byte response. Where: ^ N: DS [4u is the request content, and others are the HTTP request header.
Note: Sec-WebSocket-Key1 and Sec-WebSocket-Key2 in the old websocket protocol is not, because to determine whether the current request is websocket, mainly through the request header inWhether connection is equal to upgrade and upgrade is equal to websocket. That is to say, to determine whether a request is a websocket request, you only need to determine the connection and upgrade in the request header, determine whether the old and new versions can be passed by including Sec-WebSocket-Key1 and Sec-WebSocket-Key2 ". The following is a short section to determine whether a websocket request is required.Code:
// Note: the code is netty-based private Boolean iswebsocketreq (httprequest req) {return (httpheaders. values. upgrade. equalsignorecase (req. getheader (httpheaders. names. connection) & httpheaders. values. websocket. equalsignorecase (req. getheader (httpheaders. names. upgrade )));}
Server Response:
HTTP/1.1 101 websocket protocol handshakeupgrade: websocketconnection: upgradesec-websocket-origin: http://example.comSec-websocket-location: WS: // your sample8jks 'y: G * CO, wxa-
Divide the number in the first key of the request by the number of blank characters in the first key, and the second key is the same. Connect the two results with the last 8-byte string of the request to form a string. The server responds to the body ("8jks 'y: G * CO, wxa -") that is, the MD5 sum of the string. The following is a netty-based response Java code:
// Netty-based websocket response code private httpresponse buildwebsocketres (httprequest req) {httpresponse res = new defaulthttpresponse (httpversion. http_1_1, new httpresponsestatus (101, "Web SOCKET protocol handshake"); Res. addheader (httpheaders. names. upgrade, httpheaders. values. websocket); Res. addheader (httpheaders. names. connection, httpheaders. values. upgrade); // fill in the headers and contents depending On handshake method. if (req. containsheader (names. sec_websocket_key1) & req. containsheader (names. sec_websocket_key2) {// draft 7.5, 7.6 and protocol standard // new handshake method with a challenge: Res. addheader (names. sec_websocket_origin, req. getheader (names. origin); Res. addheader (names. sec_websocket_location, getwebsocketlocation (req); string protocol = req. getheader (names. sec_websocket_protocol); If (protocol! = NULL) {res. addheader (names. sec_websocket_protocol, Protocol);} // calculate the answer of the challenge. string key1 = req. getheader (names. sec_websocket_key1); string key2 = req. getheader (names. sec_websocket_key2); int A = (INT) (Long. parselong (getnumeric (key1)/getspace (key1 ). length (); int B = (INT) (Long. parselong (getnumeric (key2)/getspace (key2 ). length (); long c = req. getcontent (). read Long (); channelbuffer input = channelbuffers. buffer (16); input. writeint (a); input. writeint (B); input. writelong (c); channelbuffer output = NULL; try {output = channelbuffers. wrappedbuffer (messagedigest. getinstance ("MD5 "). digest (input. array ();} catch (nosuchalgorithmexception e) {logger. error ("No such algorithm: MD5.", e) ;}res. setcontent (output);} else {// The oldest websocket protocol // old handshake me Thod with no challenge: If (req. getheader (names. Origin )! = NULL) {res. addheader (names. websocket_origin, req. getheader (names. origin);} res. addheader (names. websocket_location, getwebsocketlocation (req); string protocol = req. getheader (names. websocket_protocol); If (protocol! = NULL) {res. addheader (names. websocket_protocol, protocol) ;}} return res ;}// remove all non-numeric private string getnumeric (string Str) {return Str. replaceall ("\ D", "") ;}// return the space private string getspace (string Str) {return Str. replaceall ("\ s ","");}
Postscript:
Recently we found that chrome14 and ff6.5 use the latest websocket draft 10 Protocol. That is to say, the code in the above example does not support the handshake protocol of draft 10. The Protocol variable of the Draft operator is relatively large, for example, if the transmission is performed by frame and the frame bit has permission check, you can view my other article in detail.Article: Http://blog.csdn.net/fenglibing/article/details/6852497
This article is from:Feng Libin's blog