zoukankan      html  css  js  c++  java
  • 使用php创建WebSocket服务

    执行方法:
    首先先修改server.php与index.html的ip
    通过命令行执行 [php路径]php.exe "[文件路径]server.php"
    然后通过浏览器打开index.html

    <?
    include 'websocket.class.php';
    
    $config=array(
    'address'=>'192.168.0.200',
    'port'=>'8000',
    'event'=>'WSevent',//回调函数的函数名
    'log'=>true,
    );
    $websocket = new websocket($config);
    $websocket->run();
    function WSevent($type,$event){
     global $websocket;
    if('in'==$type){
    $websocket->log('客户进入id:'.$event['k']);
    }elseif('out'==$type){
    $websocket->log('客户退出id:'.$event['k']);
    }elseif('msg'==$type){
    $websocket->log($event['k'].'消息:'.$event['msg']);
    roboot($event['sign'],$event['msg']);
    }
    }
    
    function roboot($sign,$t){
     global $websocket;
     switch ($t)
    {
     case 'hello':
     $show='hello,GIt @ OSC';
    break;
     case 'name':
    $show='Robot';
    break;
     case 'time':
     $show='当前时间:'.date('Y-m-d H:i:s');
    break;
     case '再见':
     $show='( ^_^ )/~~拜拜';
    $websocket->write($sign,'Robot:'.$show);
    $websocket->close($sign);
    return;
    break;
     case '天王盖地虎':
     $array = array('小鸡炖蘑菇','宝塔震河妖','粒粒皆辛苦');
     $show = $array[rand(0,2)];
    break;
    default:
     $show='( ⊙o⊙?)不懂,你可以尝试说:hello,name,time,再见,天王盖地虎.';
    }
    $websocket->write($sign,'Robot:'.$show);
    }
    ?>
    
    <?php
    
    
    class websocket{
     public $log;
     public $event;
     public $signets;
     public $users; 
     public $master; 
     public function __construct($config){
     if (substr(php_sapi_name(), 0, 3) !== 'cli') {
    die("请通过命令行模式运行!");
    }
    error_reporting(E_ALL);
    set_time_limit(0);
    ob_implicit_flush();
     $this->event = $config['event'];
     $this->log = $config['log'];
     $this->master=$this->WebSocket($config['address'], $config['port']);
    $this->sockets=array('s'=>$this->master);
    }
     function WebSocket($address,$port){
     $server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
     socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1);
     socket_bind($server, $address, $port);
    socket_listen($server);
     $this->log('开始监听: '.$address.' : '.$port);
     return $server;
    }
     function run(){
    while(true){
    $changes=$this->sockets;
    @socket_select($changes,$write=NULL,$except=NULL,NULL);
     foreach($changes as $sign){
    if($sign==$this->master){
    $client=socket_accept($this->master);
    $this->sockets[]=$client;
     $user = array(
    'socket'=>$client,
    'hand'=>false,
    );
     $this->users[] = $user;
    $k=$this->search($client);
     $eventreturn = array('k'=>$k,'sign'=>$sign);
    $this->eventoutput('in',$eventreturn);
    }else{
    $len=socket_recv($sign,$buffer,2048,0);
    $k=$this->search($sign);
    $user=$this->users[$k];
    if($len<7){
    $this->close($sign);
     $eventreturn = array('k'=>$k,'sign'=>$sign);
    $this->eventoutput('out',$eventreturn);
    continue;
    }
    if(!$this->users[$k]['hand']){//没有握手进行握手
    $this->handshake($k,$buffer);
    }else{
     $buffer = $this->uncode($buffer);
     $eventreturn = array('k'=>$k,'sign'=>$sign,'msg'=>$buffer);
    $this->eventoutput('msg',$eventreturn);
    }
    }
    }
    }
    }
     function search($sign){//通过标示遍历获取id
     foreach ($this->users as $k=>$v){
    if($sign==$v['socket'])
     return $k;
    }
     return false;
    }
     function close($sign){//通过标示断开连接
     $k=array_search($sign, $this->sockets);
    socket_close($sign);
    unset($this->sockets[$k]);
    unset($this->users[$k]);
    }
     function handshake($k,$buffer){
     $buf = substr($buffer,strpos($buffer,'Sec-WebSocket-Key:')+18);
     $key = trim(substr($buf,0,strpos($buf,"rn")));
     $new_key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
     $new_message ="HTTP/1.1 101 Switching Protocolsrn";
     $new_message .="Upgrade: websocketrn";
     $new_message .="Sec-WebSocket-Version: 13rn";
     $new_message .="Connection: Upgradern";
     $new_message .="Sec-WebSocket-Accept:". $new_key ."rnrn";
    socket_write($this->users[$k]['socket'],$new_message,strlen($new_message));
    $this->users[$k]['hand']=true;
     return true;
    }
     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;
    }
     function code($msg){
     $msg = preg_replace(array('/r$/','/n$/','/rn$/',), '', $msg);
     $frame = array(); 
     $frame[0] = '81'; 
     $len = strlen($msg); 
     $frame[1] = $len<16?'0'.dechex($len):dechex($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 idwrite($id,$t){//通过id推送信息
     if(!$this->users[$id]['socket']){return false;}//没有这个标示
    $t=$this->code($t);
     return socket_write($this->users[$id]['socket'],$t,strlen($t));
    }
     function write($k,$t){//通过标示推送信息
    $t=$this->code($t);
     return socket_write($k,$t,strlen($t));
    }
     function eventoutput($type,$event){//事件回调
    call_user_func($this->event,$type,$event);
    }
     function log($t){//控制台输出
    if($this->log){
    $t=$t."rn";
     fwrite(STDOUT, iconv('utf-8','gbk//IGNORE',$t));
    }
    }
    }
  • 相关阅读:
    static final常量变量的正确书写规范
    Why aren't more desktop apps written with Qt?(quora.com系列文章)
    建议学个一知半解的时候,再看书
    C++中new和delete的背后(最后还是调用了MSVCR90的malloc)
    关于Qt的事件循环以及QEventLoop的简单使用(QEventLoop::quit()能够终止事件循环,事件循环是可以嵌套的)
    QProcess::startDetached(5.10有了一种新的方式)
    微信公众号支付开发
    Middleware

    TOKEN+签名验证
  • 原文地址:https://www.cnblogs.com/yzycoder/p/5220488.html
Copyright © 2011-2022 走看看