嗯调了一下,怎么说呢,这个代码里面有很多小问题,比如:
1、类方法调用没有用 this
2、$this->user,$this->users 混乱
3、handshake 方法里面的变量 $buffer 没有声明赋值,实际上它应该是参数 $data
4、handshake 方法里面的 $skey 变量在后面的调用中写错了
...
后面的我都没记录了,都是小问题,改了就能运行了:
http://ww4.sinaimg.cn/large/6856d0b6gw1erwxp8kij3j211e0pjqbi.jpg附上代码
服务端:
<?php
error_reporting(E_ERROR);
class ws
{
public $sock;
public $socks;
public $users;
function send($socket, $msg)
{
if ($socket === "all") {
foreach ($this->users as $key => $value) {
socket_write($this->users[ $key ]['client'], $msg, strlen($msg));
}
}
socket_write($socket, $msg, strlen($msg));
}
function handshake($socket, $data)
{
$buffer = $data;
$secretkey = substr($buffer, strpos($data, 'Sec-WebSocket-Key:') + 18);
$skey = trim(substr($secretkey, 0, strpos($secretkey, "\r\n")));
//生成返回的握手包key,后面的字符串是固定的,不知道谁规定的。。。
$newskey = base64_encode(sha1($skey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", TRUE));
$httpheader = "HTTP/1.1 101 Switching Protocols\r\n";
$httpheader .= "Upgrade: websocket\r\n";
$httpheader .= "Connection: Upgrade\r\n";
$httpheader .= "Sec-WebSocket-Accept: " . $newskey . "\r\n\r\n";
$this->send($socket, $httpheader);
$key = $this->search($socket);
$this->users[$key-1]["new"] = FALSE;
return TRUE;
}
function search($socket)
{
return array_search($socket, $this->socks);
}
function close($socket)
{
socket_close($socket);
$key = $this->search($socket);
unset($this->socks[ $key ]);
if ($key !== 0) {
unset($this->users[$key-1]);
}
return TRUE;
}
function decode($buffer) {
$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 __construct($ip, $port)
{
f('start...');
$this->sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
f('create socket...');
socket_set_option($this->sock, SOL_SOCKET, SO_REUSEADDR, 1);
f('set option...');
socket_bind($this->sock, $ip, $port);
f('bind socket...');
socket_listen($this->sock);
f('listen socket...');
$this->socks[] = $this->sock;
while (1) {
$write = NULL;
$expect = NULL;
$sockscache = $this->socks;
if (socket_select($sockscache, $write, $expect, 0) === false) {
die("socket_select() failed, reason: " . socket_strerror(socket_last_error()) . "\n");
}
foreach ($sockscache as $sockcache) {
if ($sockcache === $this->sock) {
if (($client = socket_accept($this->sock)) !== false) {
f('accept socket...');
$this->socks[] = $client;
$this->users[] = array("client" => $client, "name" => "", "new" => TRUE);
}
} else {
$length = socket_recv($sockcache, $data, 2048, 0);
f('receive socket...');
$key = $this->search($sockcache);
if ($length < 7) {
$name = $this->users[$key-1]["name"];
$this->send($sockcache, "$name 已经退出。");
$this->close($sockcache);
f('close socket...');
} else {
if ($this->users[$key-1]["new"]) {
$this->handshake($sockcache, $data);
f('handshake...');
} else {
//信息处理
$data = $this->decode($data);
echo $data;
die();
}
}
}
}
usleep(500);
}
}
}
function f($msg = '')
{
static $start = false;
if (!$start) {
ob_start();
$start = true;
}
echo date('Y-m-d H:i:s') . ":{$msg}\n";
ob_flush();
}
$websocket = new ws('127.0.0.1', '10077');
客户端:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
//<![CDATA[
var ws = new WebSocket('ws://localhost:10077/phpstorm/test2.php');
ws.onopen = function (event) {
var data = event.data;
console.log('onopen:', data, event);
};
ws.onerror = function (event) {
var data = event.data;
console.log('onerror:', data, event);
};
ws.onclose = function (event) {
var data = event.data;
console.log('onclose:', data, event);
};
ws.onmessage = function (event) {
var data = event.data;
console.log('onmessage:', data, event);
};
//]]>
</script>
</body>
</html>