php +html5 websocket 聊天室

时间:2023-03-07 18:05:08

针对内容比较长出错,修改后的解码函数 和 加码函数 原文请看上一篇 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>