Php + websocket Simple Chat Room practice, websocket Construction
1. Preface
There is a simple chat room in the company's game. After learning about it, I learned that it was implemented by node + websocket. I think php will also be used as a simple chat room. As a result, I collected various materials to read documents and find instances. I also wrote a simple chat room.
Http connections are divided into short connections and long connections. Short connections can be implemented using ajax. Long connections are websocket. Short connections are easy to implement, but consume too much resources. There are some problems with the efficiency but compatibility of websocket. Websocket is an html5 Resource
For more information about websocket persistent connections, see https://www.zhihu.com/question/20215561.
This article mainly introduces the implementation steps of websocket simple chat rooms. The in-depth introduction of some knowledge points will provide links or help readers collect their own information.
2. Front-end
Front-end websocket implementation is simple and straightforward
// Connect to websocket
Var ws = new WebSocket ("ws: // FIG: 8000 ");
// When the websoc is successfully connected
Ws. onopen = function (){}
// The message output by the server is obtained successfully.
Ws. onmessage = function (e ){}
// When a connection error occurs
Ws. onerror = function (){}
//Send data to the server
Ws. send ();
3. Background
The difficulties of websocket are mainly in the background
3.1websocket connection process
Websocket communication diagram this is a simple communication diagram between the client and the server. What php does is to accept the Encrypted key and return it to complete socket creation and handshake operations.
Is a detailed flowchart of websocket processing by the server.
3.2 code practices
The process of the server is roughly as follows:
1. Suspend A socket process to wait for connection
② Traverse socket array after socket connection
③ Perform a handshake without handshaking. If the handshake has been made, the system will receive data parsing and write the data into the buffer for output.
The following is the sample code (I wrote a class, so the code is segmented based on the function). The github address and some pitfalls I encountered are provided at the bottom of this article.
1. First, create a socket
// Create a socket public function createSocket ($ address, $ port) {// create a socket $ socket = socket_create (AF_INET, SOCK_STREAM, SOL_TCP ); // set the socket option socket_set_option ($ socket, SOL_SOCKET, SO_REUSEADDR, 1); // bind the IP address and port socket_bind ($ socket, $ address, $ port ); // listener socket socket_listen ($ socket); return $ socket ;}
2. Put the socket into an array
Public function _ construct ($ address, $ port) {// create a socket $ this-> soc = $ this-> createSocket ($ address, $ port ); $ this-> socs = array ($ this-> soc );}
3. Process suspension traverses the socket array. The main operations are completed here.
Public function run () {// pending process while (true) {$ arr = $ this-> socs; $ write = $ response T = NULL; // receive socket numbers to listen to their status socket_select ($ arr, $ write, $ response T, NULL); // traverse the socket array foreach ($ arr as $ k => $ v) {// if a new socket is created, a valid socket resource is returned. if ($ this-> soc ==$ v) {$ client = socket_accept ($ this-> soc ); if ($ client <0) {echo "socket_accept () failed";} else {// array_push ($ this-> socs, $ client ); // unset ($ this []); // put valid socket Resources in the socket array $ this-> socs [] = $ Client ;}} else {// number of bytes received from the socket from the connected socket $ byte = socket_recv ($ v, $ buff, 20480, 0); // if the received byte is 0 if ($ byte <7) continue; // if there is no handshake, the handshake is performed. if the handshake is performed, the request is processed if (! $ This-> hand [(int) $ client]) {// perform the handshake operation $ this-> hands ($ client, $ buff, $ v );} else {// data processing operations $ mess = $ this-> decodeData ($ buff); // send data $ this-> send ($ mess, $ v );}}}}}
4. the handshake process is to receive websocket content from the Sec-WebSocket-Key: to obtain the key and write it to the buffer client through the encryption algorithm for verification (automatic verification does not need to be processed)
Public function hands ($ client, $ buff, $ v) {// extract the key passed by websocket and encrypt it (this is a fixed handshake mechanism to obtain Sec-WebSocket-Key: key) $ buf = substr ($ buff, strpos ($ buff, 'sec-WebSocket-Key: ') + 18 ); // remove the line break space character $ key = trim (substr ($ buf, 0, strpos ($ buf, "\ r \ n "))); // fixed encryption algorithm $ new_key = base64_encode (sha1 ($ key. "258eafa5-e914-4710995ca-c5ab0dc85b11", true); $ new_message = "HTTP/1.1 101 Switching Protocols \ r \ n"; $ new_message. = "Upgrade: websocket \ r \ n"; $ new_message. = "Sec-WebSocket-Version: 13 \ r \ n"; $ new_message. = "Connection: Upgrade \ r \ n"; $ new_message. = "Sec-WebSocket-Accept :". $ new_key. "\ r \ n"; // write the socket into the buffer socket_write ($ v, $ new_message, strlen ($ new_message); // socket_write (socket, $ upgrade. chr (0), strlen ($ upgrade. chr (0); // mark the socket handshake success $ this-> hand [(int) $ client] = true ;}
5. parse the client data (I have not encrypted it here. You can also encrypt it as needed)
// Parse data public function decodeData ($ buff) {// $ buff parse data frames $ mask = array (); $ data = ''; $ msg = unpack ('H * ', $ buff); // use the unpack function to decode the data from binary. $ head = substr ($ msg [1 ); if (hexdec ($ head {1}) = 8) {$ data = false;} else if (hexdec ($ head {1}) = 1) {$ mask [] = hexdec (substr ($ msg [1], 4,2); $ mask [] = hexdec (substr ($ msg [1], 6,2 )); $ mask [] = hexdec (substr ($ msg [1], 8, 2); $ mask [] = hexdec (substr ($ msg [1], 10, 2 )); // The status connecting $ s = 12; $ e = strlen ($ msg [1])-2; $ n = 0 is displayed when the connection is established; for ($ I = $ s; $ I <= $ e; $ I + = 2) {$ data. = chr ($ mask [$ n % 4] ^ hexdec (substr ($ msg [1], $ I, 2); $ n ++ ;} // send data to the client // If the length is greater than 125, block the data into blocks $ block = str_split ($ data, 125 ); $ mess = array ('mess '=> $ block [0],); return $ mess ;}
6. Write the socket into the buffer.
// Send data public function send ($ mess, $ v) {// send a group foreach ($ this-> socs as $ keys => $ values) when the socket array is successfully traversed) {// use the socket resource id allocated by the system as your nickname $ mess ['name'] = "Tourist's socket: {$ v }"; $ str = json_encode ($ mess); $ writes = "\ x81 ". chr (strlen ($ str )). $ str; // ob_flush (); // flush (); // sleep (3); if ($ this-> hand [(int) $ values]) socket_write ($ values, $ writes, strlen ($ writes ));}}
7. Running Method
Github address git@github.com: rsaLive/websocket. git
① It is best to run server. php on the console
Go to the server. php script directory (you can first check php-v to see If php is configured. If there is no Linux configuration, go to bash windows to configure path)
Php-f server. php
If there is an error or misunderstanding
② Access html files through the server
8. Open debugging to check errors.
①Server. phpOutput can be printed in a suspended process. If any problem occurs, you can add printing to the Code for debugging.
You can mark in each judgment to view the code running range on the console
However, you need to re-run the script php server. php after each modification.
②
If this error occurs, it may be
1. Send data with the initial socket of the server (content cannot be sent when shaking hands with the server for the first time)
2. If the verification has been completed but the client has not sent or the message sent is empty, this will also happen.
Therefore, we need to check the data of connected sockets.
③ It may not be supported by the browser or the server does not enable socket before it starts to verify
if (window.WebSocket){ console.log("This browser supports WebSocket!");} else { console.log("This browser does not support WebSocket.");}
If any, please point out