飞嗨,欢迎您的光临,本博所发布之文章皆为作者亲测通过,如有错误,欢迎通过各种方式指正。(本博已于2015.12.6升级到php7,运行环境php7 php-fpm + nginx1.8.0)

html5新api websocket初探

Node.js/JS lf 1945℃ 0评论

我去,一不小心,30天没有更新博客了.倒不是加班忙的没空写,而是,觉得东西太碎片化了,无从写起.最近,把鸟哥私房菜的linux基础篇看完了(主要是利用上下班地铁时间),现在在看服务器篇了.写上一篇文章时,服务器还在微软云,给微软试用了一年,现在收费了,于是,花钱买了阿里云的ecs,照样是centos 7系统,apache svn mysql redis memcache环境.只买了1M带宽,所以前些日子,把本博客以前的图片和soft.feehi.com的图片都丢到七牛云存储上了,不然1M带宽加载图片会慢死.

一直很喜欢socket编程,可惜这是php的软肋,无数次想拿起c,写linux下的c socket,但是总是被js linux php给牵绊住,没有那么多经历.最近看到html5也提供socket长链接了,很开森…不过html提供的是封装好的websocket,不是完全自定义socket.没办法,就我那丢丢c java知识,服务器端是写不了socket,只有用php写server端的socket了.结果,折腾了两天.终于,服务器端只能与单个客户端通信了,但是第二个客户端死活进不去,想了很多办法,也请教了公司其他同事,还是卡在这里.没办法,那就先把单个客户端与服务器端通信的过程整理一下,期待谁告诉我一下php server端的socket怎么与多个客户端同时通信.

php socket server端:

<?php
ob_implicit_flush();
$addrss = '127.0.0.1';
$port = 9111;
$server = socket_create(AF_INET , SOCK_STREAM , SOL_TCP);
socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($server , $addrss , $port);
socket_listen($server , 10);
$clients[] = $server;
tip("server started and listening on $port $server\n");
$blank = false;
while(true){
socket_select($clients,$write=NULL,$except=NULL,NULL);
//echo "e\n";
foreach($clients as $k => $sock){
//连接主机的client
if($sock == $server){
$client = socket_accept($server);
if($client < 0){
echo 'socket_accept() failed\n';
continue;
}else{
$clients[] = $client;
echo "connect client\n";
continue;
}
}else{
//$len = socket_recv($sock , $buffer , 2048 , 0);
$len=socket_recv($sock,$buffer,2048,0);
if($len < 7){
unset($clients[$k]);
continue;
}
if(!$blank){
$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($sock,$new_message,strlen($new_message));
$blank = true;
}else{//echo 11111111111111111111111111111;die;
$str = decode($buffer);
echo "received data:$str\n";
$msg = 'hello client';
$msg = code($msg);
socket_write($sock,$msg,strlen($msg));
}

}
//$client = socket_accept($server);
//$buffer = socket_read($client, 8192);
}
}
//}
function tip($tip){
$tip = date('Y-m-d H:i:s').' : '.$tip;
echo iconv('utf-8','gbk//IGNORE',$tip);
}
function decode($buffer) {
$len = $masks = $data = $decoded = null;
$len = ord($buffer[1]) & 127;

if ($len === 126) {
$masks = substr($buffer, 4, 4);
$data = substr($buffer, 8);
} else if ($len === 127) {
$masks = substr($buffer, 10, 4);
$data = substr($buffer, 14);
} else {
$masks = substr($buffer, 2, 4);
$data = substr($buffer, 6);
}
for ($index = 0; $index < strlen($data); $index++) {
$decoded .= $data[$index] ^ $masks[$index % 4];
}
return $decoded;
}
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] = 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;
}

javascript socket客户端(我修改了windows的hosts文件,把blog.f.com解析到127.0.0.1):

<script src='jquery-1.8.2.min.js'></script>
<script>
function ini()
{
var content = 'initial';
var host = 'ws://blog.f.com:9111/server.php';
socket = new WebSocket(host);
socket.onopen = function(){
//alert(socket.readyState);
//alert('socket has been opened');
socket.send(content);
}
socket.onmessage = function(msg){
alert(msg.data);
}

}
function sendChat(){
var content = $('textarea').val();
//alert(content);
socket.send(content);
}
</script>
<body onload='ini()'>
<textarea></textarea>
<input type='button' value='发送' onclick='sendChat($(this))'>
</body>

首先,在dos下执行php server.php启动9111端口箭头监听

php socket server

php socket server

打开浏览器客户端,向服务器发送数据

html5 websocket

html5 websocket

向服务器发送数据,服务器也收到了,服务器给客户端发送数据

server-client

server-client

单个客户端和服务器端建立socket链接正常,也能正常通信,但是当再开一个客户端时,就死活链接不上,chrome的js console报错:Uncaught InvalidStateError: Failed to execute ‘send’ on ‘WebSocket': Still in CONNECTING state.真心无奈.调试发现,当第二个客户端链接时,连while循环都没有进去.谁若是有解,一定请留言告诉我,谢谢!!!

转载请注明:飞嗨 » html5新api websocket初探

喜欢 (2)or分享 (0)
发表我的评论
取消评论
表情
粤ICP备15018643号-1