纯测试。不要注册用户,进去直接说话。左边的主题列表实时刷新。
http://geekav.com支持 Chrome / Firefox / Safari。
=======================================
先看 Ajax,假设我们会用 $.post 某字串 s 给 a.php,然后回调某函数 f ( )。
换成 WebSocket 后,你先需要在服务器上运行一个独立的 WS server,假设开在 8080 端口上。
这个 WS server 可以用任何办法做,node.js 之类都可以,我比较怕麻烦就还是用 php,可以用 Ratchet 给 php 加 WS 支持。
未来所有 client 也连接到这个 WS server 上,然后可以方便地做双向通讯和广播。例如 client 端代码:
$socket = new WebSocket('ws://xxx.xxx.xxx.xxx:8080');
$socket.onerror = function(e) {
console.log('WebSocket error: ' + e.data);
};
$socket.onopen = function(e) {
};
$socket.onmessage = function(e) {
$socket.send('client received the msg');
console.log(e.data);
};
server 端代码,假设名字是 ws.php:
class WS_SERVER implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
$conn->send('hello');
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e) {
$conn->close();
}
public function onMessage(ConnectionInterface $conn, $msg) {
echo $msg;
}
}
$server = IoServer::factory(new WsServer(new WS_SERVER()), 8080);
$server->run();
然后在 server 运行 php ws.php。
这里有一个问题,原始的 php 代码怎么和这个 ws.php 通讯?例如我们怎么知道应该在什么时候把什么信息广播给所有 client?
这个可以在服务器本机自连接一下,未来 scaling 可能也更好做。
客户 == [Ajax] ==> a.php == [WS] ==> ws.php == [WS] ==> 客户
或者也可以更彻底一点,把 Ajax 调用和所有逻辑都改成走 WS。
客户 == [WS] ==> ws.php == [WS] ==> 客户
还有一个问题是传 session。这个想了想可以用 ws 的路径解决。client 这样连接:$socket = new WebSocket('ws://xxx.xxx.xxx.xxx:8080/' + session_id()); 这里 session_id() 函数从 document.cookie 里面读出来 session id。
然后 server 用 $mcache->get('memc.sess.key.'.substr($conn->WebSocket->request->getPath(), 1)) 就可以从 memcached 里面把对应的 session 数据读出来,再自己 parse 成 array。如果是用数据库存 session 可以照样做。
下面看转换 Ajax 调用。client 上写三个全局变量:var $socket; var $socket_uid = 0; var $socket_callback = new Array();
然后 client 上写一个
function ws_post(post_msg, post_callback) {
post_msg.id = $socket_uid;
$socket.send(JSON.stringify(post_msg));
$socket_callback[$socket_uid] = function(msg) {post_callback(msg)};
$socket_uid++;
}
然后 server 上就可以处理并且把正确的东西返回去,并且同时通知所有 client:
public function onMessage(ConnectionInterface $conn, $msg) {
$msg = json_decode($msg, true);
$conn->send($msg['id'].','.process($conn, $msg));
foreach ($this->clients as $client) {
if ($client != $conn) // 这个信息发给其他用户
$client->send('-1,'.$conn->remoteAddress);
}
}
然后 client 上可以正确地调用回调函数:
$socket.onmessage = function(e) {
var x = e.data.indexOf(',');
var n = e.data.substr(0, x);
var d = e.data.substr(x+1);
if (n == '-1')
console.log('a guy from ' + d + ' sent a msg to server');
else
$socket_callback[n](d);
};
嗯,就是这样了。