PHP websocket学习笔记

2018-07-14T19:11:00
<?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-&gt;socketList[(int)$this->mainSocket] = $this->mainSocket;
    }

    // 运行
    public function run() {

        // 让服务不停止
        while (true) {
            $read&nbsp;&nbsp;=&nbsp;$this->socketList;
            $write&nbsp;=&nbsp;$except = null;
            // 删除不活跃的socket
            $status&nbsp;=&nbsp;socket_select($read, $write,&nbsp;$except, null);
            if (!$status) continue;

            foreach ($read&nbsp;as&nbsp;$socket) {
                // 第一次来访问
                if ($this-&gt;mainSocket&nbsp;==&nbsp;$socket) {
                    // 得到客户端的socket
                    $clientSocket&nbsp;=&nbsp;socket_accept($socket);
                    // 获取客户端头信息进行握手操作
                    $headData&nbsp;=&nbsp;socket_read($clientSocket, 8000);
                    handshaking($headData,&nbsp;$clientSocket);

                    socket_getpeername($clientSocket,&nbsp;$addr, $port);

                    // 把客户端的一个socket存入队列中
                    $this-&gt;socketList[(int)$clientSocket] = $clientSocket;
                    $read[(int)$clientSocket]             = $clientSocket;
                    // 删除掉
                    unset($read[(int)$this->mainSocket]);

                    // 注册一个事件
                    if ($this->onConnection) {
                        call_user_func($this-&gt;onConnection,&nbsp;$clientSocket);
                    }
                } else {
                    // 获得客户发送过来的数据
                    $buf&nbsp;=&nbsp;socket_read($socket, 8000);
                    // 关闭或异常
                    if ($buf&nbsp;===&nbsp;&#39;&#39;&nbsp;||&nbsp;$buf === false) {
                        // 删除掉队列它socket
                        unset($read[(int)$socket]);
                        unset($this-&gt;socketList[(int)$socket]);
                        if ($this->onClose){
                            call_user_func($this->onClose);
                        }
                        socket_close($socket);
                        continue;
                    }else{
                        if ($this->onMessage){
                            call_user_func($this-&gt;onMessage,$socket,$buf);
                        }
                    }
                }
            }//End foreach
        }// End while
    }//End run


}


$server = new Ws();

// 连接
$server-&gt;onConnection&nbsp;=&nbsp;function&nbsp;($socket){
    $msg&nbsp;=&nbsp;(int)$socket."欢迎进入web60聊天室 !";
    socket_write($socket,enmask($msg));
};
// 会话
$server-&gt;onMessage&nbsp;=&nbsp;function&nbsp;($socket,$data){
    $msg&nbsp;=&nbsp;unmask($data);
    // 广播给所有人 聊天室
    broadcast($msg);
};

$server->run();


/**
 * @param $msg 广播的消息
 */
function broadcast($msg){

    global $server;
    foreach ($server-&gt;socketList&nbsp;as&nbsp;$socket){
        $tmp&nbsp;=&nbsp;enmask((int)$socket.'说:'.$msg);
        @socket_write($socket,$tmp);
    }
}


/**
 * @param $header       客户端头信息
 * @param $activeSocket 客户端的socket对象
 */
function handshaking($header,&nbsp;$activeSocket) {
    preg_match("/Sec-WebSocket-Key:&nbsp;(.+)rn/", $header,&nbsp;$matchs);
    $key&nbsp;&nbsp;=&nbsp;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&nbsp;.=&nbsp;&quot;Sec-WebSocket-Accept:&nbsp;{$key}rnrn"; // 最后的一定要有两个回车
    // 握手响应协议信息返回给浏览器
    socket_write($activeSocket,&nbsp;$head);
}

//解码数据
function unmask($text) {
    $length&nbsp;=&nbsp;ord($text[1]) & 127;
    if ($length == 126) {
        $masks&nbsp;=&nbsp;substr($text, 4, 4);
        $data&nbsp;&nbsp;=&nbsp;substr($text, 8);
    } elseif ($length == 127) {
        $masks&nbsp;=&nbsp;substr($text, 10, 4);
        $data&nbsp;&nbsp;=&nbsp;substr($text, 14);
    } else {
        $masks&nbsp;=&nbsp;substr($text, 2, 4);
        $data&nbsp;&nbsp;=&nbsp;substr($text, 6);
    }
    $text = "";
    for ($i&nbsp;=&nbsp;0;&nbsp;$i < strlen($data);&nbsp;++$i) {
        $text&nbsp;.=&nbsp;$data[$i]&nbsp;^&nbsp;$masks[$i % 4];
    }
    return $text;
}

// 加码数据
function enmask($str) {
    $a&nbsp;&nbsp;=&nbsp;str_split($str, 125);
    $ns = "";
    foreach ($a&nbsp;as&nbsp;$o) {
        $ns&nbsp;.=&nbsp;&quot;\x81&quot;&nbsp;.&nbsp;chr(strlen($o)) . $o;
    }
    return $ns;
}
?>
当前页面是本站的「Baidu MIP」版。发表评论请点击:完整版 »