PHP websocket学习笔记
<?php
<?php
class Ws {
// 服务器端的socket
private $mainSocket;
// socket队列
public $socketList = [];
// 连接事件
public $onConnection;
// 会话事件
public $onMessage;
// 关闭事件
public $onClose;
// 构造函数
public function __construct() {
// 创建socket
$this->mainSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// IP和端口重用
socket_set_option($this->mainSocket, SOL_SOCKET, SO_REUSEADDR, 1);
// 绑定
socket_bind($this->mainSocket, '0.0.0.0', 6060);
// 监听
socket_listen($this->mainSocket, 5);
// 把服务器端的socket存入socket队列
$this->socketList[(int)$this->mainSocket] = $this->mainSocket;
}
// 运行
public function run() {
// 让服务不停止
while (true) {
$read = $this->socketList;
$write = $except = null;
// 删除不活跃的socket
$status = socket_select($read, $write, $except, null);
if (!$status) continue;
foreach ($read as $socket) {
// 第一次来访问
if ($this->mainSocket == $socket) {
// 得到客户端的socket
$clientSocket = socket_accept($socket);
// 获取客户端头信息进行握手操作
$headData = socket_read($clientSocket, 8000);
handshaking($headData, $clientSocket);
socket_getpeername($clientSocket, $addr, $port);
// 把客户端的一个socket存入队列中
$this->socketList[(int)$clientSocket] = $clientSocket;
$read[(int)$clientSocket] = $clientSocket;
// 删除掉
unset($read[(int)$this->mainSocket]);
// 注册一个事件
if ($this->onConnection) {
call_user_func($this->onConnection, $clientSocket);
}
} else {
// 获得客户发送过来的数据
$buf = socket_read($socket, 8000);
// 关闭或异常
if ($buf === '' || $buf === false) {
// 删除掉队列它socket
unset($read[(int)$socket]);
unset($this->socketList[(int)$socket]);
if ($this->onClose){
call_user_func($this->onClose);
}
socket_close($socket);
continue;
}else{
if ($this->onMessage){
call_user_func($this->onMessage,$socket,$buf);
}
}
}
}//End foreach
}// End while
}//End run
}
$server = new Ws();
// 连接
$server->onConnection = function ($socket){
$msg = (int)$socket."欢迎进入web60聊天室 !";
socket_write($socket,enmask($msg));
};
// 会话
$server->onMessage = function ($socket,$data){
$msg = unmask($data);
// 广播给所有人 聊天室
broadcast($msg);
};
$server->run();
/**
* @param $msg 广播的消息
*/
function broadcast($msg){
global $server;
foreach ($server->socketList as $socket){
$tmp = enmask((int)$socket.'说:'.$msg);
@socket_write($socket,$tmp);
}
}
/**
* @param $header 客户端头信息
* @param $activeSocket 客户端的socket对象
*/
function handshaking($header, $activeSocket) {
preg_match("/Sec-WebSocket-Key: (.+)rn/", $header, $matchs);
$key = base64_encode(sha1($matchs[1] . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));
$head = "HTTP/1.1 101 Switching Protocolsrn";
$head .= "Upgrade: websocketrn"; // 告诉这个websocket客户端可以把这个协议升级为websocket协议
$head .= "Connection: Upgradern"; // 升级这个通信协议
$head .= "Sec-WebSocket-Accept: {$key}rnrn"; // 最后的一定要有两个回车
// 握手响应协议信息返回给浏览器
socket_write($activeSocket, $head);
}
//解码数据
function unmask($text) {
$length = ord($text[1]) & 127;
if ($length == 126) {
$masks = substr($text, 4, 4);
$data = substr($text, 8);
} elseif ($length == 127) {
$masks = substr($text, 10, 4);
$data = substr($text, 14);
} else {
$masks = substr($text, 2, 4);
$data = substr($text, 6);
}
$text = "";
for ($i = 0; $i < strlen($data); ++$i) {
$text .= $data[$i] ^ $masks[$i % 4];
}
return $text;
}
// 加码数据
function enmask($str) {
$a = str_split($str, 125);
$ns = "";
foreach ($a as $o) {
$ns .= "\x81" . chr(strlen($o)) . $o;
}
return $ns;
}
?>
当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »