websocket 聊天机器人

websocket.class.php:

<?php
header("Content-type: text/html; charset=utf-8");
/* 
创建类websocket($config); 
$config结构: 
$config=array( 
  'address'=>'192.168.0.200',//绑定地址 
  'port'=>'8000',//绑定端口 
  'event'=>'WSevent',//回调函数的函数名 
  'log'=>true,//命令行显示记录 
); 
  
回调函数返回数据格式 
function WSevent($type,$event) 
  
$type字符串 事件类型有以下三种 
in  客户端进入 
out 客户端断开 
msg 客户端消息到达 
均为小写 
  
$event 数组 
$event['k']内置用户列表的userid; 
$event['sign']客户标示 
$event['msg']收到的消息 $type='msg'时才有该信息 
  
方法: 
run()运行 
search(标示)遍历取得该标示的id 
close(标示)断开连接 
write(标示,信息)推送信息 
idwrite(id,信息)推送信息 
  
属性: 
$users 客户列表 
结构: 
$users=array( 
[用户id]=>array('socket'=>[标示],'hand'=[是否握手-布尔值]), 
[用户id]=>arr..... 
) 
*/  
   
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);  
	}

	public 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;  
	}

    public 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);  
                }  
            }  
          }  
        }  
	}

	public function search($sign) {//通过标示遍历获取id
		foreach ($this->users as $k => $v) {
			if($sign == $v['socket']) {
			    return $k;
			}
         }  
        return false;  
	}  

	public function close($sign) {//通过标示断开连接  
        $k=array_search($sign, $this->sockets);  
        socket_close($sign);  
        unset($this->sockets[$k]);  
        unset($this->users[$k]);  
	} 

	public function handshake($k,$buffer) {  
        $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));  
        $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->users[$k]['socket'],$new_message,strlen($new_message));  
        $this->users[$k]['hand']=true;  
        return true;  
	}

    public 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;  
	}

	public 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):dechex($len);  
        $frame[2] = $this->ord_hex($msg);  
        $data = implode('',$frame);  
        return pack("H*", $data);  
	}

    public function ord_hex($data) {    
        $msg = '';    
        $l = strlen($data);    
        for($i= 0; $i<$l; $i++) {    
            $msg .= dechex(ord($data{$i}));    
        }      
        return $msg;    
    }  
   
    public 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));  
	}

    public function write($k,$t) {//通过标示推送信息  
      $t=$this->code($t);  
      return socket_write($k,$t,strlen($t));  
    }  
    public function eventoutput($type,$event) {//事件回调  
        call_user_func($this->event,$type,$event);  
	}

    public function log($t) {//控制台输出  
        if($this->log) {  
            $t=$t."\r\n";  
            fwrite(STDOUT, iconv('utf-8','gbk//IGNORE',$t));  
        }  
    }  
}
server.php:

<?php 
header("Content-type: text/html; charset=utf-8");
include 'websocket.class.php';  
   
$config = array(  
  'address'=>'10.16.77.216',  
  'port'=>'8008',  
  'event'=>'WSevent',//回调函数的函数名  
  'log'=>true,  
);  
$websocket = new websocket($config);  
$websocket->run();  
function WSevent($type, $event){ 
  global $websocket;  
    if ('in' == $type) {  
      $websocket->log('客户进入id: ' . $event['k']);  
    } else if ('out' == $type) {  
      $websocket->log('客户退出id: ' . $event['k']);  
    } else if ('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);  
}

index.html:

    

<!doctype html>  
<html>  
<head>  
<meta charset="utf-8">  
<title>websocket_TEST</title>  
</head>  
<body>  
<textarea class="log" style="width: 100%; height: 500px;">  
=======websocket======  
</textarea>  
<input type="button" value="连接" onClick="link()">   
<input type="button" value="断开" onClick="dis()">  
<input type="text" id="text">  
<input type="button" value="发送" onClick="send()">  
<script type="text/javascript" src="jquery-1.7.1.min.js"></script>  
<script>  
function link(){  
  var url='ws://10.16.77.216:8008';  
  socket=new WebSocket(url);  
  socket.onopen=function(){log('连接成功')}  
  socket.onmessage=function(msg){log('获得消息:'+msg.data);console.log(msg);}  
  socket.onclose=function(){log('断开连接')}  
}  
function dis(){  
  socket.close();  
  socket=null;  
}  
function log(var1){  
  $('.log').append(var1+"\r\n");  
}  
function send(){  
  socket.send($('#text').val());  
}  
function send2(){  
  var json = JSON.stringify({'type':'php','msg':$('#text').val()})  
  socket.send(json);  
}  
</script>  
</body>  
</html>
运行界面:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值