This article mainly introduces the example of using websocket in php. For more information, see
The following figure shows the handshake between the client and the server when a websocket connection is established. This part can be easily completed in node, because the net module provided by node has encapsulated socket sockets, developers only need to consider data interaction instead of connection creation. Php does not, from socket connection, establishment, binding, listening, etc., all of which need to be operated by ourselves, so it is necessary to come up with it. ① And ② are actually an HTTP request and response, but what we get during the processing is a string that has not been parsed. For example, the Code is as follows: GET/chat HTTP/1.1 Host: server. example. comOrigin: The http://www.jb51.com we often see is like this, when this thing comes to the server side, we can get this information directly through some code libraries. 1. Processing websocket WebSocket connections in php is actively initiated by the client, so everything should proceed from the client. The first step is to parse the Sec-WebSocket-Key string sent from the client. The Code is as follows: GET/chat HTTP/1.1 Host: server. example. comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ = Origin: http://www.jb51.comSec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13 The format of the client request first sets up a socket connection in php to listen to the port information. 1. the establishment of a socket connection refers to the establishment of a socket. I believe that many people who have completed computer networks in the university know the establishment of a connection. The following is a process of establishing a connection: the code is as follows: // create a socket $ master = socket_create (AF_INET, SOCK_STREAM, SOL_TCP); socket_set_option ($ master, SOL_SOCKET, SO_REUSEADDR, 1); socket_bind ($ master, $ address, $ port); socket_listen ($ master); compared with node, the processing in this place is too troublesome. The above lines of code have not been connected, but these codes are something that must be written to build a socket. Because the processing process is a little complicated, I wrote various processing into a class to facilitate management and calling. The Code is as follows: // demo. phpClass WS {var $ master; // connect to the server's client var $ sockets = array (); // var $ handshake = false for socket management in different States; // determine whether to shake hands function _ construct ($ address, $ port) {// create a socket $ this-> master = socket_create (AF_INET, SOCK_STREAM, SOL_TCP) or die ("socket_create () failed"); socket_set_option ($ this-> master, SOL_SOCKET, SO_REUSEADDR, 1) or die ("socket_option () failed"); socket_bind ($ This-> master, $ address, $ port) or die ("socket_bind () failed"); socket_listen ($ this-> master, 2) or die ("socket_listen () failed "); $ this-> sockets [] = $ this-> master; // debug echo (" Master socket :". $ this-> master. "\ n"); while (true) {// The socket automatically selected for the message. If it is a handshake, the host is automatically selected $ write = NULL; $ response T = NULL; socket_select ($ this-> sockets, $ write, $ response T, NULL); foreach ($ this-> sockets as $ socket) {// connect the client to the host If ($ socket = $ this-> master) {$ client = socket_accept ($ this-> master); if ($ client <0) {// debug echo "socket_accept () failed"; continue;} else {// connect ($ client); array_push ($ this-> sockets, $ client ); echo "connect client \ n" ;}} else {$ bytes = @ socket_recv ($ socket, $ buffer, 2048,0); if ($ bytes = 0) return; if (! $ This-> handshake) {// if there is no handshake, shake hands first to respond // doHandShake ($ socket, $ buffer); echo "shakeHands \ n ";} else {// If the handshake has been made, directly accept the data and process $ buffer = decode ($ buffer); // process ($ socket, $ buffer ); echo "send file \ n" ;}}}} the above Code has been debugged by me. It's not a big problem. If you want to test it, you can type php/path/to/demo in the cmd command line. php; of course, the above is just a class. If you want to test it, you have to create a new instance. The Code is as follows: $ ws = new WS ('localhost', 4000); the client code can be slightly simpler: the code is as follows: var ws = new WebSocket ("ws: // localhost: 4000 "); ws. onopen = function () {console. log ("handshake successful") ;}; ws. onerror = function () {console. log ("error") ;}; run the server code. when the client is connected, we can see: 2. the code for extracting Sec-WebSocket-Key information is as follows: function getKey ($ req) {$ key = null; if (preg_match ("/Sec-WebSocket-Key :(. *) \ r \ n/", $ req, $ match) {$ key = $ match [1];} return $ key;} This is relatively simple, straight The websocket header must contain the Sec-WebSocket-Key, so it is quick to match ~ 3. the code for encrypting the Sec-WebSocket-Key is as follows: function encry ($ req) {$ key = $ this-> getKey ($ req); $ mask = "258eafa5-e914-4710995ca-c5ab0dc85b11 "; return base64_encode (sha1 ($ key. '258eafa5-E914-47DA-95CA-C5AB0DC85B11 ', true);} re-encrypts the string after SHA-1. If the encryption algorithm is incorrect, the client will directly report an error during the verification: 4. response to Sec-WebSocket-Accept code: function dohandshake ($ socket, $ req) {// obtain the encryption key $ acceptKey = $ this-> encry ($ req ); $ upgrade = "HTTP/1.1 101 Switching Protocols \ r \ n ". "Upgrade: websocket \ r \ n ". "Connection: Upgrade \ r \ n ". "Sec-WebSocket-Accept :". $ acceptKey. "\ r \ n ". "\ r \ n"; // write socket socket_write (socket, $ upgrade. chr (0), strlen ($ upgrade. chr (0); // indicates that the handshake is successful. Data is used for receiving data next time. Frame format $ this-> handshake = true;} You must note that each request and corresponding format has an empty row, namely \ r \ n, I lost this item at the beginning of the test and had a long struggle. After the client successfully verifies the key, the onopen function is triggered: 5. the data frame processing code is as follows: // parse the data frame function decode ($ buffer) {$ len = $ masks = $ data = $ decoded = null; $ len = ord ($ buffer [1]) & 127; if ($ len = 126) {$ masks = substr ($ buffer, 4, 4 ); $ data = substr ($ buffer, 8);} else if ($ len = 127) {$ masks = substr ($ buffer, 10, 4 ); $ data = substr ($ buffer, 14);} else {$ masks = substr ($ buffer, 2, 4); $ data = substr ($ buffer, 6 );} for ($ index = 0; $ index <strlen ($ data); $ index ++) {$ decoded. = $ data [$ index] ^ $ masks [$ index % 4];} return $ decoded;} encoding problems mentioned in the previous article are not described here, php has too many character processing functions, and I don't remember it clearly. Here we haven't provided a detailed description of the decoding program, so we can directly return the data sent by the client as is, it can be regarded as a chat room model. The Code is as follows: // 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;} // return data function send ($ client, $ msg) {$ msg = $ this-> frame ($ msg ); socket_write ($ client, $ msg, strlen ($ msg);} client code: Code: var ws = new WebSocket ("ws: // localhost: 4000 "); ws. onopen = function () {Console. log ("handshake successful") ;}; ws. onmessage = function (e) {console. log ("message:" + e. data) ;}; ws. onerror = function () {console. log ("error") ;}; ws. send ("Li Jing"); after the connection, the server returns the data as it is: 2. Note problem 1. for websocket Version problems, the client has the Sec-WebSocket-Version: 13 in the handshake request. This Version ID is an upgraded Version, which is used by browsers. In the previous versions, data encryption is more troublesome. It sends two keys: GET/chat HTTP/1.1 Host: server. example. comUpgrade: websocketConnection: UpgradeOrigin: http://www.jb51.netSec-WebSocket-Protocol: chat, superchatSec-WebSocket-Key1: xxxxSec-WebSocket-Key2: xxxx if it is this version (older, no longer in use ), the following code needs to be obtained: function encry ($ key1, $ key2, $ l8b) {// Get the numbers preg_match_all ('/([\ d] +) /', $ key1, $ key1_num); preg_match_all ('/([\ d] +)/', $ key2, $ Key2_num); $ key1_num = implode ($ key1_num [0]); $ key2_num = implode ($ key2_num [0]); // Count spacespreg_match_all ('/([] +) /', $ key1, $ key1_spc); preg_match_all ('/([] +)/', $ key2, $ key2_spc ); if ($ key1_spc = 0 | $ key2_spc = 0) {$ this-> log ("Invalid key"); return ;} // Some math $ key1_sec = pack ("N", $ key1_num/$ key1_spc); $ key2_sec = pack ("N", $ key2_num/$ key2_spc ); return md5 ($ keydomainsec. $ key2_sec. $ l8b, 1);} can only spit this Verification Method! Compared to nodeJs websocket operation method: Code: // server program var crypto = require ('crypto'); var WS = '258eafa5-E914-47DA-95CA-C5AB0DC85B11 '; require ('net '). createServer (function (o) {var key; o. on ('data', function (e) {if (! Key) {// handshake key = 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); 2. data Frame Parsing Code this article does not provide data Frame Parsing Code such as decodeFrame. The format of the data frame. Parsing is purely physical.