classwebsocket{public$log;public$event;public$signets;public$users;public$master;public$obj;publicfunction__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->obj=$config['obj'];$this->master=$this->WebSocket($config['address'],$config['port']);$this->sockets=array('s'=>$this->master);}functionWebSocket($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;}functionrun(){while(true){$changes=$this->sockets;@socket_select($changes,$write=NULL,$except=NULL,NULL);foreach($changesas$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);}}}}}functionsearch($sign){//通过标示遍历获取idforeach($this->usersas$k=>$v){if($sign==$v['socket'])return$k;}returnfalse;}functionclose($sign){//通过标示断开连接$k=array_search($sign,$this->sockets);socket_close($sign);unset($this->sockets[$k]);unset($this->users[$k]);}functionhandshake($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.1101SwitchingProtocols\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;returntrue;}functionuncode($str){$mask=array();$data='';$msg=unpack('H*',$str);$head=substr($msg[1],0,2);if(hexdec($head{1})===8){$data=false;}elseif(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;}functioncode($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);returnpack("H*",$data);}functionord_hex($data){$msg='';$l=strlen($data);for($i=0;$i<$l;$i++){$msg.=dechex(ord($data{$i}));}return$msg;}functionidwrite($id,$t){//通过id推送信息if(!$this->users[$id]['socket']){returnfalse;}//没有这个标示$t=$this->code($t);returnsocket_write($this->users[$id]['socket'],$t,strlen($t));}functionwrite($k,$t){//通过标示推送信息$t=$this->code($t);returnsocket_write($k,$t,strlen($t));}functioneventoutput($type,$event){//事件回调call_user_func(array($this->obj,$this->event),$this,$type,$event);}functionlog($t){//控制台输出if($this->log){$t=$t."\r\n";fwrite(STDOUT,$t);}}}

server.php

<?phpinclude('websocket.class.php');$config=array('address'=>'192.168.1.12','port'=>'8000','event'=>'WSevent',//回调函数的函数名'log'=>true,);$websocket=newwebsocket($config);$websocket->run();functionWSevent($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']);}}functionroboot($sign,$t){global$websocket;switch($t){case'hello':$show='hello,GIt@OSC';break;case'name':$show='Robot';break;case'time':$show='当前时间:'.date('Y-m-dH: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 server.php



index.html

<!doctypehtml><html><head><metacharset="utf-8"><title>websocket_TEST</title></head><body><ahref="index2.html">index2</a><textareaclass="log"></textarea><inputtype="button"value="连接"onClick="link()"><inputtype="button"value="断开"onClick="dis()"><inputtype="text"id="text2"><inputtype="button"value="发送"onClick="send2()"><scriptsrc="http://jt.hiooy.com/hsshop/js/jquery.js?v=59"></script><script>functionlink(){varurl='ws://192.168.1.12:8000';socket=newWebSocket(url);socket.onopen=function(){log('连接成功')}socket.onmessage=function(msg){log('获得消息:'+msg.data);console.log(msg);}socket.onclose=function(){log('断开连接')}}functiondis(){socket.close();socket=null;}functionlog(var1){$('.log').append(var1+"\r\n");}functionsend(){socket.send($('#text').attr('value'));}functionsend2(){varjson=JSON.stringify({'type':'php','msg':$('#text2').attr('value')})socket.send(json);}</script></body></html>