php与WebSocket结合实时输出日志
设计思路
后端:通过workerman开启socket,监控会话,发现会话以后,读取当前日志的文件大小并把指针移到文件最后面,开始监控文件变化。
每秒钟刷新20次 然后跳出,有变化返回给前端。(这里如果不跳出会造成进程阻塞,不要在会话时写死循环!!!)
前端:每秒钟一次的心跳策略,获取信息。
PHP实现
通过composer方式安装workman
{ "require": { "walkor/workerman": "^3.5" } }
<?php require_once './vendor/autoload.php'; use Workerman\Worker; define("MAX_SHOW", 8192); $ws_worker = new Worker("websocket://0.0.0.0:8936"); // 启动4个进程对外提供服务 $ws_worker->count = 4; $ws_worker->onMessage = function ($connection, $data) { if ($data == "tom") $connection->send("连接成功。"); // 定义要查看的log文件路径 $file_name = "/www/wwwlogs/access.log"; $connection->send("日志文件:" . $file_name); $file_size = filesize($file_name); $file_size_new = 0; $add_size = 0; $ignore_size = 0; $fp = fopen($file_name, "r"); fseek($fp, $file_size); $num = 0; while (1) { $num++; clearstatcache(); $file_size_new = filesize($file_name); $add_size = $file_size_new - $file_size; if ($add_size > 0) { if ($add_size > MAX_SHOW) { $ignore_size = $add_size - MAX_SHOW; $add_size = MAX_SHOW; fseek($fp, $file_size + $ignore_size); } $connection->send(fread($fp, $add_size)); $file_size = $file_size_new; } usleep(50000); if ($num > 20) break; } fclose($fp); }; // 运行worker Worker::runAll();
JS代码
socket WebSocket
<script src='//cdn.bootcss.com/socket.io/1.3.7/socket.io.js'></script>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="Creative - Bootstrap 3 Responsive Admin Template"> <meta name="author" content="GeeksLabs"> <meta name="keyword" content="Creative, Dashboard, Admin, Template, Theme, Bootstrap, Responsive, Retina, Minimal"> <title>Show Log</title> </head> <body style="background-color:oldlace"> <p>等待任务..</p> <input value='' id='v' type="text" style="display:none;"> <!--<button type="button" onclick=a() >Click Me!</button>--> <br/> <div> <textarea readonly id="txt" style="width: 100%; height: 635px;background: black none repeat scroll 0% 0%; color: rgb(153, 153, 153);"></textarea> </div> </body> </html> <script src='//cdn.bootcss.com/socket.io/1.3.7/socket.io.js'></script> <script> ws = new WebSocket("ws://xxx.xxx.xxx:8936"); //ip地址或者访问域名 ws.onopen = function () { ws.send('tom'); }; ws.onmessage = function (e) { oTest = document.getElementById("txt"); oTest.innerHTML = oTest.innerHTML + e.data; oTest.scrollTop = oTest.scrollHeight; // 此处实现tail -f 日志展示效果 }; window.setInterval(a, 1000); // 心跳 function a() { r = document.getElementById("v"); ws.send(v.value); } </script>
解决https站点无法使用ws问题
https有证书,那么只能使用wss方式连接服务端。那么wss只需要输入域名即可,剩下的端口转发交给后端Nginx去做就ok。
首先确认服务器的websocket端口是开放的(主要是确认下云服务器的安全组是否开放)。
我们主要利用Nginx伪静态方式转发端口,伪静态如下:
location /socket { proxy_pass http://127.0.0.1:8936; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; }
然后在js上连接代码调整为域名方式,示例如下:
ws = new WebSocket("wss://baidu.com/socket"); //ip地址或者访问域名
这里需要注意的是/socket 要与 伪静态的/socket 一模一样,否则连接失败
废话不多说了,放上代码片段地址:https://gitee.com/ripperts/websocketlog.git
评论