php +html5 websocket 聊天室
针对内容比较长出错,修改后的解码函数 和 加码函数 原文请看上一篇 http://yixun.yxsss.com/yw3104.html
function uncode($str,$key){ $mask = array(); $data = ''; $msg = unpack('H*',$str); $head = substr($msg[1],0,2); if ($head == '81' && !isset($this->slen[$key])) { $len=substr($msg[1],2,2); $len=hexdec($len); if(substr($msg[1],2,2)=='fe'){ $len=substr($msg[1],4,4); $len=hexdec($len); $msg[1]=substr($msg[1],4); }else if(substr($msg[1],2,2)=='ff'){ $len=substr($msg[1],4,16); $len=hexdec($len); $msg[1]=substr($msg[1],16); } $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; $n=0; }else if($this->slen[$key] > 0){ $len=$this->slen[$key]; $mask=$this->ar[$key]; $n=$this->n[$key]; $s = 0; } $e = strlen($msg[1])-2; for ($i=$s; $i<= $e; $i+= 2) { $data .= chr($mask[$n%4]^hexdec(substr($msg[1],$i,2))); $n++; } $dlen=strlen($data); if($len > 255 && $len > $dlen+intval($this->sjen[$key])){ $this->ar[$key]=$mask; $this->slen[$key]=$len; $this->sjen[$key]=$dlen+intval($this->sjen[$key]); $this->sda[$key]=$this->sda[$key].$data; $this->n[$key]=$n; return false; }else{ unset($this->ar[$key],$this->slen[$key],$this->sjen[$key],$this->n[$key]); $data=$this->sda[$key].$data; unset($this->sda[$key]); return $data; } } function code($msg){ $frame = array(); $frame[0] = '81'; $len = strlen($msg); if($len < 126){ $frame[1] = $len<16?'0'.dechex($len):dechex($len); }else if($len < 65025){ $s=dechex($len); $frame[1]='7e'.str_repeat('0',4-strlen($s)).$s; }else{ $s=dechex($len); $frame[1]='7f'.str_repeat('0',16-strlen($s)).$s; } $frame[2] = $this->ord_hex($msg); $data = implode('',$frame); return pack("H*", $data); }
其中主函数run 里面的接收修改为
do{ $l=socket_recv($sock,$buf,1000,0); $len+=$l; $buffer.=$buf; }while($l==1000);
服务器端代码:
var fs = require('fs') , http = require('http') , socketio = require('socket.io'); var server = http.createServer(function(req, res) { res.writeHead(200, { 'Content-type': 'text/html'}); res.end(fs.readFileSync(__dirname + '/index.html')); }).listen(8080, function() { console.log('Listening at: http://localhost:8080'); }); var ids=[]; var io=socketio.listen(server); io.on('connection', function (socket) { ids.push(socket.id); socket.on('key', function (msg) { console.log('Message Received: ', msg); console.log('sockid:'+socket.id); console.log(ids); io.sockets.socket(ids[0]).emit('key',msg);//向指定的用户发信息 //socket.broadcast.emit('key', msg); //公告 //socket.emit('key', msg); //发给自己 }); socket.on('disconnect',function(){ console.log('关闭'+socket.id); }); });
客服端:
<!doctype html> <html> <head> <title>sss</title> <meta charset="utf-8"> <script src="/socket.io/socket.io.js"></script> <script> var socket = io.connect('http://localhost:8080'); socket.on('key', function (data) { document.getElementById('nr').innerHTML+=data.aa+'<br>'; }); function send(){ var v=document.getElementById('sss').value; socket.emit('key',{'aa':v}); } </script> </head> <body> <div id="nr"> </div> <input type="text" id="sss"> <button 0nClick="send();">发送</button> </body> </html>
最近弄html5最新功能WebSocket 网上找了很多资料 都是相互抄袭 而且用不了,经过2天的折腾 终于好了,不过还有昵称是中文名的时候会自动断了的问题 估计是转码的问题。
php 的 WebSocket 13 服务器的代码
<?php error_reporting(E_ALL); ob_implicit_flush(); $sk=new Sock('127.0.0.1',8000); $sk->run(); class Sock{ public $sockets; public $users; public $master; public function __construct($address, $port){ $this->master=$this->WebSocket($address, $port); $this->sockets=array('s'=>$this->master); } function run(){ while(true){ $changes=$this->sockets; socket_select($changes,$write=NULL,$except=NULL,NULL); foreach($changes as $sock){ if($sock==$this->master){ $client=socket_accept($this->master); //$key=uniqid(); $this->sockets[]=$client; $this->users[]=array( 'socket'=>$client, 'shou'=>false ); }else{ $len=socket_recv($sock,$buffer,2048,0); $k=$this->search($sock); if($len<7){ $name=$this->users[$k]['ming']; $this->close($sock); $this->send2($name,$k); continue; } if(!$this->users[$k]['shou']){ $this->woshou($k,$buffer); }else{ $buffer = $this->uncode($buffer); $this->send($k,$buffer); } } } } } function close($sock){ $k=array_search($sock, $this->sockets); socket_close($sock); unset($this->sockets[$k]); unset($this->users[$k]); $this->e("key:$k close"); } function search($sock){ foreach ($this->users as $k=>$v){ if($sock==$v['socket']) return $k; } return false; } 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->e('Server Started : '.date('Y-m-d H:i:s')); $this->e('Listening on : '.$address.' port '.$port); return $server; } function woshou($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]['shou']=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 send($k,$msg){ /*$this->send1($k,$this->code($msg),'all');*/ parse_str($msg,$g); $this->e($msg); $ar=array(); if($g['type']=='add'){ $this->users[$k]['ming']=$g['ming']; $ar['add']=true; $ar['nrong']='欢迎'.$g['ming'].'加入!'; $ar['users']=$this->getusers(); $key='all'; }else if($g['type']=='ltiao'){ $ar['nrong']=$g['nr']; $key=$g['key']; } $msg=json_encode($ar); $this->e($msg); $msg = $this->code($msg); $this->send1($k,$msg,$key); //socket_write($this->users[$k]['socket'],$msg,strlen($msg)); } function getusers(){ $ar=array(); foreach($this->users as $k=>$v){ $ar[$k]=$v['ming']; } return $ar; } function send1($k,$str,$key='all'){ if($key=='all'){ foreach($this->users as $v){ socket_write($v['socket'],$str,strlen($str)); } }else{ if($k!=$key) socket_write($this->users[$k]['socket'],$str,strlen($str)); socket_write($this->users[$key]['socket'],$str,strlen($str)); } } function send2($ming,$k){ $ar['remove']=true; $ar['removekey']=$k; $ar['nrong']=$ming.'退出聊天室'; $str = $this->code(json_encode($ar)); $this->send1(false,$str,'all'); } function e($str){ $path=dirname(__FILE__).'/log.txt'; $str=$str."\n"; error_log($str,3,$path); echo iconv('utf-8','gbk//IGNORE',$str); } } ?>
接上一篇 html的代码
<!doctype html> <html> <head> <meta charset="utf-8"> <title>socket</title> <style type="text/css"> #cc,#cb{margin:10px auto; width:800px; border:solid 1px #CCCCCC; height:500px; font-size:14px;} #cc p{line-height:1.8; margin:0px; padding:0px;} #cb{height:30px; border:0px;} #aaad{display:none;} #aaas{display:block;} .a{color:#008040;} .e{color:#F33;} .b{color:#333;} .c{color:#999;} #autors{float:right; width:200px; height:480px; padding:10px 0px; overflow:auto; background-color:#F2F2F2;} #content{float:left; width:580px; height:480px; padding:10px; } #autors a{display:block; line-height:25px; color:#03C; text-decoration:none; padding:0px 10px;} #autors .userck,#autors a:hover{background-color:#999; color:#FFF;} </style> </head> <body> <div id="cc"> <div id="content"></div> <div id="autors"> <a href="javascript:;" 0nClick="ac('all',this)" class="userck">所有人</a> </div> </div> <div id="cb"> <p id="aaas"> <span class="an1">设置昵称:</span> <input type="text" maxlength="10" size="10" id="nicheg"> <input type="button" value="进入聊天室" 0nClick="aa()"> </p> <p id="aaad"> <input type="text" maxlength="50" size="50" id="texts"> <input type="button" value="发送" 0nClick="ab()"> <input type="button" value="退出聊天室" 0nClick="az()"> </p> </div> <script src="http://www.yxsss.com/ui/p/a.js" type="text/javascript"></script> <script> var socket=null,content=A.$('content'),autors=A.$('autors'),key='all',user=[]; var an1s=document.getElementsByClassName('an1'),an2s=document.getElementsByClassName('an2'); function aa(){ var url='ws://localhost:8000'; var ming=A.$('nicheg').value.trim(); if(ming==''){ alert('昵称不能为空'); return false; } socket=new WebSocket(url); socket.onopen=function(){ if(socket.readyState==1){ socket.send('type=add&ming='+ming); }else{ content.appendChild('<p class="e">进入失败!<p>'); } } socket.onmessage=function(msg){ eval('var da='+msg.data); if(da.add){ for(i in da.users){ if(typeof(user[i])=='undefined'){ var ob=A.$$('<a href="javascript:;" 0nClick="ac(\''+i+'\',this)">'+da.users[i]+'</a>'); user[i]=ob; autors.appendChild(ob); } } A.$('aaad').style.display='block'; A.$('aaas').style.display='none'; } if(da.remove){ user[da.removekey].del(); content.appendChild(A.$$('<p class="c">'+da.nrong+'</p>')); return ; } content.appendChild(A.$$('<p class="b">'+da.nrong+'</p>')); } socket.onclose=function(){ content.appendChild(A.$$('<p class="c">退出聊天室</p>')); } } function ac(k,t){ key=k; t.parentNode.children.rcss('userck',''); t.rcss('','userck'); } function ab(){ socket.send('type=ltiao&nr='+A.$('texts').value+'&key='+key); } function az(){ socket.close(); socket=null; } </script> </body> </html>
原创文章请随便转载。愿和大家分享,并且一起进步。-- 江 coder