为了实现web页面推送消息,接触到了 workerman,官方各种插件,虽然各种文档也都有,但我毕竟没什么PHP功底,看文档也很吃力,只能靠运行文档里的代码理解workerman的各种功能,所以,刚刚接触的头一个星期搞的自己云里雾里……
好不容易才摸索出了一点点经验,但还是有一些不能理解的地方,希望各位老大们看到有机会能把我理解不正确的地方指正一下,谢谢先。
先说自己的理解吧,这个对新人应该很有用(大师、老鸟们可以直接无视):
要实现纯粹基于workerman推送消息到web客户端,好像只能靠客户端的js接收,这是前提。
我目前只摸索出2种方法,第一种最简单:
1.完全靠客户端的js和workerman服务器来实现推送,和web服务器端无关;
2.web服务器端将要推送的消息内容发送给workerman服务器,再由workerman服务器将消息推送给客户端。
下面上代码<这些代码亲测可以在chrome和appache+PHP5.5上运行>:
方法一
1.PHP cli代码——push.php(本文件请放在workerman目录之上)
<?php
require_once __DIR__ .'/Workerman/Autoloader.php';
use Workerman\Worker;//是先name space,还是先use?不能理解
// 初始化一个worker容器,监听1234端口,只能使用websocket协议
// !!!必须,要不然客户端不能接受推送消息!!!
$worker = new Worker('websocket://0.0.0.0:1234');
$worker->count = 1;
$worker->name = 'wjy-Test';//设置这个 workerman 的名字
$worker->onWorkerStart = function($worker){
global $worker;
echo ('workerman is running...');
};
// 当有客户端发来消息时执行的回调函数下面2行写法都是一个效果
$worker->onMessage = function($connection, $data)use($worker){
//$worker->onMessage = function($connection, $data){
global $worker;
broadcast($data."<br />".$connection->id.":".$connection->getRemoteIp());
//下面这句只向当前连接发送消息
//$connection->send($data."<br />".$connection->id.":".$connection->getRemoteIp());
};
// 向所有用户推送数据
function broadcast($message){
global $worker;
foreach($worker->connections as $con){
$con->send($message);
}
}
// 运行所有的 worker(其实当前只定义了一个)
Worker::runAll();
push.php结束,该代码在linux命令行下执行php push.php start开启
2.web服务器端文件——index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>workerman websocked推送</title>
<script src="/assets/js/jquery.js"></script>
</head>
<body>
<h2>示例:workerman websocked推送</h2>
请输入推送内容:
<input type="input" id="push_content" />
<input type="submit" id="push_button" value="推送" />
<hr />
<p>下面是服务器主动推送的内容:</p>
<div id="server_msg" style="height:400px;border:1px solid blue;"></div>
<script>
var ws = new WebSocket('ws://192.168.1.30:1234');
ws.onopen=function(){
ws.send("web start msg");
}
ws.onmessage = function(e){
//document.getElementById("server_msg").innerHTML=e.data;
$("#server_msg").html(e.data);
};
$("#push_button").click(function(){
var str=$('#push_content').val();
ws.send(str);
ws.onmessage=function(e){
$("#server_msg").html(e.data);
}
});
</script>
</body>
</html>
方法二
1.PHP cli代码——push.php(本文件请放在workerman目录之上)
<?php
require_once __DIR__ .'/Workerman/Autoloader.php';
use Workerman\Worker;
// 初始化一个worker容器,监听1234端口,只能使用websocket协议
// !!!必须,要不然客户端不能接受推送消息!!!
$worker = new Worker('websocket://0.0.0.0:1234');
$worker->count = 1;
$worker->name = 'wjy-Test';//设置这个 workerman 的名字
$worker->onWorkerStart = function($worker){
global $worker;
//当worker开始运行时,再开启一个内部端口,使 appache里的php代码 能向 php-cli 发送数据,tcp协议
//这个worker应该可以使用很多其它协议,我没试过,官方代码里使用过text协议,其它我没试过
echo "workerman is running...";
$inner_worker = new Worker('tcp://0.0.0.0:5678');
$inner_worker->listen();
$inner_worker->onMessage = function($connection, $msg){
return broadcast($msg ? $msg : 'fail');
};
};
// 向所有用户推送数据
function broadcast($message){
global $worker;
foreach($worker->connections as $con){
$con->send($message);
}
}
// 运行所有的 worker
Worker::runAll();
push.php结束,该代码在linux命令行下执行 php push.php start 开启
2.web服务器端文件——index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>workerman -> apache向worker推送</title>
<script src="/jquery.js"></script>
</head>
<body>
<h2>示例:apache向workerman推送</h2>
请输入推送内容:
<form method="post" action="./s.php">
<input type="input" name="push_content" id="push_content" />
<input type="submit" id="push_button" value="推送" />
</form>
<hr />
<p>下面是服务器主动推送的内容:</p>
<div id="server_msg" style="height:400px;border:1px solid blue;"></div>
<script>
$().ready(function(){
var ws = new WebSocket('ws://192.168.1.30:1234');
ws.onmessage = function(e){
//document.getElementById("server_msg").innerHTML=e.data;
$("#server_msg").html(e.data);
};
});
</script>
</body>
</html>
3.web服务器端文件——s.php
<?php
header("Content-type: text/html; charset=utf-8");
// 建立 连接到worker内部推送端口5678
$client = stream_socket_client('tcp://192.168.1.30:5678', $errno, $errmsg, 1);
// 推送的数据,包含uid字段,表示是给这个uid推送
$data = $_POST["push_content"];
// 发送数据
fwrite($client,$data);
// 读取推送结果
echo fread($client)
//fclose($client);好像不能写这一行,会出错,不解
?>
好了,所有代码结束。
最后,我有两个疑惑,
1、workerman如何知道一个客户端是不是在线呢?比如某个客户把页面开后就不动了,放了几个小时,这几个小时里,电脑有可能会休眠,或者windows自动锁屏等很多不可预料的事情发生。workerman如何判断?
2、workerman广播时,内部有没有机制知道当前有多少客户端在线?还是不管现在有多少客户端在线,就直接从id0到最后一个id全部发送