websocket.class.php
| <?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,"\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; | |
| } | |
| 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$/','/\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); | |
| } | |
| 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."\r\n"; | |
| fwrite(STDOUT, iconv('utf-8','gbk//IGNORE',$t)); | |
| } | |
| } | |
| } | |
?>
server.php
	  1 <?php
  2 include 'websocket.class.php';
  3 $config=array(
  4   'address'=>'10.77.50.111',
  5   'port'=>'12345',
  6   'event'=>'WSevent',//回调函数的函数名
  7   'log'=>true,
  8 );
  9 $websocket = new websocket($config);
 10 $websocket->run();
 11 function WSevent($type,$event){
 12 print_r($event);
 13   global $websocket;
 14     if('in'==$type){
 15       $websocket->log('客户进入id:'.$event['k']);
 16     }elseif('out'==$type){
 17       $websocket->log('客户退出id:'.$event['k']);
 18     }elseif('msg'==$type){
 19       $websocket->log($event['k'].'消息:'.$event['msg']);
 20       roboot($event['sign'],$event['msg']);
 21     }
 22 }
 23
 24 function roboot($sign,$t){
 25   global $websocket;
 26   switch ($t)
 27   {
 28   case 'hello':
 29     $show='hello,GIt @ OSC';
 30     break;
 31   case 'name':
 32     $show='Robot';
 33     break;
 34   case 'time':
 35     $show='当前时间:'.date('Y-m-d H:i:s');
 36     break;
 37   case '再见':
 38     $show='( ^_^ )/~~拜拜';
 39     $websocket->write($sign,'Robot:'.$show);
 40     $websocket->close($sign);
 41     return;
 42     break;
 43   case '天王盖地虎':
	 44     $array = array('小鸡炖蘑菇','宝塔震河妖','粒粒皆辛苦');
 45     $show = $array[rand(0,2)];
 46     break;
 47   default:
 48     $show=$t.'( ⊙o⊙?)不懂,你可以尝试说:hello,name,time,再见,天王盖地虎.';
 49   }
 50   $websocket->write($sign,'Robot:'.$show);
 51 }
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="http://h5.hejian.com/js/lib/jquery-2.1.1.min.js"></script>
<script>
function link(){
  var url='ws://10.77.50.111:12345';
  alert('ok');
  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').attr('value'));
  socket.send($('#text').val());
}
function send2(){
  var json = JSON.stringify({'type':'php','msg':$('#text2').attr('value')})
  socket.send(json);
}
</script>
</body>
</html>

