This code is based on the TP framework,
The server-side command line runs PHP index.php Home/ws/start.
Note Change the code
Socket code
<?php
namespace Home\controller;
Use Think\controller;
Use Home\controller\rediscontroller;
Class Wssocketcontroller {
Storage Connection Resources
Private $clients;
Main port
Private $master;
Customer Resources
Private $user;
Private $ip;
Private $port;
Private $redis;
Public function __construct ($socketHandle) {
$this->master = $socketHandle;
$this->clients = Array (' s ' = = $this->master);
$this->redis = Rediscontroller::connect ();
}
Monitor sockets
function Run () {
while (true) {
$read = $this->clients;
Socket_select ($read, $write = null, $except = NULL, NULL);
foreach ($read as $r) {
if ($r = = $this->master) {
Set up a four-step handshake protocol
There is a client new incoming connection coming in
Determine if the server socket is activated
Accept the client and add him to the customer array
$this->clients[] = $newCli = socket_accept ($this->master);
$this->user[] = array (' handle ' =>false);
$pid = Posix_getpid (). ' _ '. Count ($this->user);
$this->redis->sadd (' PID ', $pid);
} else {
An existing connection sends a message to all client data read
Read line break or 1024 bytes
Silent error message Although the client displays an error when disconnecting
$buffer = ";
$data = Socket_recv ($r, $buffer, 2048,0);
Check if the client is disconnected
if ($data < 7) {
Delete Client as Customer array
$this->close ($R);
Continue
}
$k = $this->search ($r);
if ($this->user[$k [' handle '] = = False) {//Only four-step handshake protocol is performed and the browser sends a WS-Protocol request
$this->handshake ($k, $buffer); Returns the WS-Protocol answer
} else {//has already established the WS-Protocol to get messages sent through WS
$pid = Posix_getpid (). ' _ '. Count ($this->user);
$str = $this->uncode ($buffer). ' __ '. $pid;
$this->sendall ($str, $r); Send Message Broadcast
}
}
}
}
}
/*
* Send WS protocol, establish WS-Protocol link
* @param int Socket Index
* @param the content of the request protocol sent by a string ws
*/
Private function Handshake ($k, $buffer) {
Get key and generate a new key
$buf = substr ($buffer, Strpos ($buffer, ' Sec-websocket-key: ') +18);
$key = Trim (substr ($buf, 0,strpos ($buf, "\ r \ n")));
$new _key = Base64_encode (SHA1 ($key. ") 258eafa5-e914-47da-95ca-c5ab0dc85b11 ", true));
Return HTTP protocol
$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\r\n";
Socket_write ($this->clients[$k], $new _message,strlen ($new _message));
$this->user[$k [' handle '] = true;
return true;
}
/*
* Mass Message
* Content sent @param a string
* @param resource A resource connection to send a message
*/
Private Function Sendall ($STR, $socket) {
Put all this customer in the customer array (except for the first one, which is a listening socket)
foreach ($this->clients as $send _sock) {
If the resource is equal to the server or is equal to its own skip,
if ($send _sock = = $this->master)//| | $send _sock = = $socket
Continue
Send a message to another user
$data = $this->code ($STR);
Socket_write ($send _sock, $data, strlen ($data));
}
}
/*
* Find Socket Resource Index
* @param Resource Socket Resource Index
*
*/
Private Function Search ($sign) {
foreach ($this->user as $k = + $v) {
if ($sign = = $v [' socket ']
return $k;
// }
$k = Array_search ($sign, $this->clients);
return $k;
}
/*
* Disconnect Sockt Connection
* @param resource Socket Resource connection
*/
Privatefunction Close ($sign) {//Disconnect by marking
$k = Array_search ($sign, $this->clients);
Socket_close ($sign); Disconnected connections need to be manually shut down on the server side
unset ($this->user[$k]);
unset ($this->clients[$k]);
}
/*
*
*WS Information decoding
* @param string string
*/
Private Function Uncode ($STR) {
$mask = Array ();
$data = ";
$msg = Unpack (' h* ', $str);
$head = substr ($msg [1],0,2);
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));
$s = 12;
$e = strlen ($msg [1])-2;
$n = 0;
for ($i = $s; $i <= $e; $i + = 2) {
$data. = Chr ($mask [$n%4]^hexdec (substr ($msg [1], $i, 2)));
$n + +;
}
}
return $data;
}
Information overweight
function code ($MSG) {
$msg = preg_replace (Array ('/\r$/', '/\n$/', '/\r\n$/',), ', $msg);
$frame = Array ();
$frame [0] = ' 81 ';
$len = strlen ($msg);
$frame [1] = $len <16? ' 0 '. Dechex ($len):d Echex ($len);
$frame [2] = $this->ord_hex ($msg);
$data = Implode (' ', $frame);
Return Pack ("h*", $data);
}
function Ord_hex ($data) {
$msg = ";
$l = strlen ($data);
for ($i = 0; $i < $l; $i + +) {
$msg. = Dechex (Ord ($data {$i}));
}
return $msg;
}
function log ($t) {//console output
$t = $t. " \ r \ n ";
Fwrite (STDOUT, Iconv (' Utf-8 ', ' Gbk//ignore ', $t));
}
}
Background Process Code:
<?php
Running the domain CLI mode
namespace Home\controller;
Use Think\controller;
Class Pcntlcontroller
{
Maximum number of open processes
Private $size;
//
Private $currSize =0;//Current number of processes
Program objects that run
Private $pro;
How to Run
Private $run;
Public Function __construct () {
$this->daemonize ();
}
/*
* Constructor function
* @param string Object
* @param string Method name
* @param int number of child processes to open
*
*/
Public function set ($controller, $active, $size) {
$this->size = $size;
$this->pro = $controller;
$this->run = $active;
}
/*
* Process daemon function, leaving the process out of the current terminal control so that the background runs independently.
*
*/
function Daemonize () {
$pid = Pcntl_fork ();//Create Child process
if ($pid = =-1) {
Exit (' Create process failed ');
} else if ($pid > 0) {
Let the parent process exit. To open a new session
Exit (0);
}
Set up a new reply-to-detach terminal that is different from the terminal, preventing the process from being killed when exiting the terminal
Posix_setsid ();
$pid = Pcntl_fork ();
if ($pid = =-1) {
Die (' Create process failed ');
} else if ($pid > 0) {
The parent process launches the remaining subprocess as a standalone process, which is managed by the system to manage this process
Exit (0);
}
}
Run the program
Public Function Start () {
Looping through the creation of child processes
while (true) {
$clientPid = Pcntl_fork ();//Create Child process
if ($clientPid = =-1) {
File_put_contents ('/usr/local/nginx/html/youquwei/log.txt ', ' Create process failed ');
} else if ($clientPid > 0) {//Parent process Program
$this->currsize++;
if ($this->currsize >= $this->size) {
$sunpid = pcntl_wait ($status);
$this->currsize--;
// }
// }
Sub-process Program execution
Work process, child process
$run = $this->run;
$this->pro-> $run ();
// }
$pid = Pcntl_fork ();
if ($pid ==0) {
for ($i =0; $i < $this->size; $i +) {
$pid = Pcntl_fork ();
if ($pid = = 0) {
$run = $this->run;
$this->pro-> $run ();
}else if ($pid = =-1) {
File_put_contents ('/usr/local/nginx/html/youquwei/log.txt ', ' Create process failed ');
}
}
if ($pid > 0) {
$p = pcntl_wait ($status);
}
}
}
}
To run the code:
<?php
Running the domain CLI mode
namespace Home\controller;
Use Think\controller;
Use Home\controller\pcntlcontroller;
Use Home\controller\wssocketcontroller;
Class Wscontroller
{
Socket Listener Handle
Private $socketHandle;
Private $ip;
Private $port;
Process
Private $pcntl;
Socket
Private $socket;
Public function __construct ($ip = "192.168.0.130", $port = 8080) {
$this->pcntl= New Pcntlcontroller;
$this->ip = $ip;
$this->port = $port;
Ob_implicit_flush ();
Error_reporting (1);
Set_time_limit (0);
$this->sockethandle = $this->websocket ();
$this->socket = new Wssocketcontroller ($this->sockethandle);
}
Establishing a server-side connection
Public Function WebSocket () {
$server = Socket_create (Af_inet, Sock_stream, sol_tcp);
Socket_set_option ($server, Sol_socket, SO_REUSEADDR, 1);
Socket_bind ($server, $this->ip, $this->port);
Socket_listen ($server);
return $server;
}
Public Function Start () {
$this->pcntl->set ($this->socket, ' Run ', 3);
$this->pcntl->start ();
$this->socket->run ();
}
}
Front page code:
<!doctype html>
<meta charset= "Utf-8" >
<title>websocket_TEST</title>
<body>
<!--
Socket process:
1: Server-side open port waits for client to establish TCP connection
2: Client establishes TCP four-time Handshake Protocol TCP connection (TCP four-time handshake connection All encapsulated code processing)
3: Client initiates WS-Protocol
4: The server determines that the client sends the message content is a WS-Protocol request
5: Server-side return WS-Connection protocol
6: Both sides establish WS long Connection
7: At this point the client can accept the content pushed by the server (accept WS-Encrypted content), or can send content to the server (the service side decodes the WS-Encrypted content).
Both sides close the socket
-
<textarea class= "Log" style= "width:100%; height:500px; " >
=======websocket======
</textarea>
<input type= "button" value= "link" onclick= "link ()" >
<input type= "button" value= "disconnect" onclick= "dis ()" >
<input type= "text" id= "text" >
<input type= "button" value= "Send" onclick= "Send ()" >
<script type= "Text/javascript" src= "Http://cdn.bootcss.com/jquery/1.11.2/jquery.min.js" ></script>
<script>
function link () {
var url= ' ws://127.0.0.1:8080 ';
Socket=new WebSocket (URL);
Socket.onopen=function () {
Log (' connection successful ');
}
Socket.onmessage=function (msg) {
Log (' Get message: ' +msg.data);
Console.log (msg);
}
Socket.onclose=function () {log (' disconnected ')}
}
function dis () {
Socket.close ();
Socket=null;
}
function log (var1) {
$ ('. log '). Append (var1+ "\ r \ n");
}
function Send () {
Socket.send ($ (' #text '). Val ());
}
</script>
</body>
An example of a simple PHP process plus a socket plus WS