WebSocket 使用PHP实现的类

前面的文章是借鉴的                                                                                                                                                                                             

<?php
/**
 * @Author: FatKee
 * @Date:   2019-01-09 12:42:28
 * @Last Modified by:   FatKee
 * @Last Modified time: 2019-01-10 16:37:13
 */


class WebSocket{
    //socket池
    private $sockets = [];
    //用户池
    private $users = [];
    //主sock
    private $master = NULL;
    //当前错误
    private $error = '';
    public function __construct($host ,$port){
        $this->master = socket_create(AF_INET,SOCK_STREAM,SOL_TCP  );
        if($this->master === false){
            $this->error = 'socket create error';
            exit;
        }
        if(socket_bind($this->master,$host,$port) === false){
            $this->error = 'socket bind error';
             exit;
        }

        if(socket_listen($this->master) === false){
            $this->error = 'socket listen  error';
             exit;
        }
        $this->sockets[] = $this->master;
        $this->e('start:'.$host.'port:' . $port);


    }
    public function run(){
        while(true){
            $sockets = $this->sockets;
            $write = NULL;
            $except = NULL;
            socket_select($sockets,$write,$except,NULL);

            foreach($sockets as $sock){
                if($sock == $this->master){
                    //等待新用户
                    $k = uniqid();
                    $this->e('user:'. $k . ' 加入用户池');
                    $new_sock = socket_accept($this->master);


                    $this->users[$k] = array('socket' => $new_sock, 'is_hand' => false );
                    $this->sockets[]  = $new_sock;

                }else{
                    //接收消息的或者关闭链接
                    $k = $this->search($sock);
                    if($this->users[$k]['is_hand'] === false){
                        //进行握手
                        $this->handshake($sock);
                        $this->users[$k]['is_hand'] = true;
                        $this->e('user:'. $k . ' 握手成功');
                          continue;
                    }
                    //读取
                    $byte=socket_recv($sock, $buff,20480, 0);
                    if($byte<7){
                        $this->e('user:'. $k . ' 退出');
                        $this->close($k);
                        continue;
                    }

                    //$this->e('user:'. $k . ' 发送消息');
                    //转发消息给别人
                    $this->e($k.'群发:'.$this->decode($buff));
                    $this->qunfa($sock,$this->decode($buff));
                }

            }
        }
    }

    private function qunfa($sock,$str){
        foreach ($this->users as  $v) {
            if($v['socket'] != $sock)
            $this->send($v['socket'],$str);
        }
    }
    //寻找socket的key
    private function search($sock){
        foreach($this->users as $k=>$v){
            if($v['socket'] == $sock){
                return $k;
            }
        }
    }

    private function handshake($sock){
        $c = socket_read($sock,1024);
        preg_match('/Sec-WebSocket-Key:(.*)/um',$c,$str);
        if(isset($str[1])){
        $new_key = base64_encode(sha1(trim($str[1])."258EAFA5-E914-47DA-95CA-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\r\n";
        socket_write($sock,$new_message,strlen($new_message));
        }
    }
    //关闭链接
    private function close($k){
        socket_close($this->users[$k]['socket']);
        unset($this->users[$k]);
        $this->sockets = [];
        $this->sockets[] = $this->master;
        foreach($this->users as $v){
            $this->sockets[] = $v['socket'];
        }
    }

    public function e($str){

        echo iconv('UTF-8','GB2312',$str) . "\r\n";
    }

    //解析数据
    private function decode($buff){
        $arr['fin'] = ord($buff[0]) >> 7;
        $arr['mask'] = ord($buff[1])>>7;
        $arr['len'] = bindec(substr(decbin(ord($buff[1])),1,7));
        if($arr['len'] == 126){
            $arr['len'] = ord($buff[2]) + ord($buff[3]) ;
            $maskkey = substr($buff,4,4);
            $data = substr($buff,8);
        }
        if($arr['len'] == 127){
            $arr['len'] = ord($buff[2]) + ord($buff[3]) + ord($buff[4])+ ord($buff[5]);
            $maskkey = substr($buff,10,4);
            $data = substr($buff,14);
        }
        if($arr['len']<=125){
            $maskkey = substr($buff,2,4);
            $data = substr($buff,6);
        }
        $a = "";
        for($i = 0 ; $i<strlen($data);$i++){
            $a .= $data[$i] ^ $maskkey[$i%4];
        }
        return $a;
    }
    private function send($sock,$str){
        $bf ="\x81".chr(strlen($str)).$str;
        socket_write($sock,$bf,strlen($bf));
    }
}

$socket = new WebSocket('192.168.2.188',1234);

$socket->run();

                                                                                                                                                                                                                

posted @ 2019-01-10 16:41  发记丶  阅读(595)  评论(0)    收藏  举报