一、安装workerman
命令运行:
composer require topthink/think-worker (或 composer require workerman/workerman)
二、配置config/worker_server.php文件里面的worker_class参数(注意:反斜杠不能写错),如下图所示:
三、在上图worker_class参数路径创建文件worker.php,如下图所示:
文件内容如下:
LANG-PHPwww.hilo8.com
- <?php
- namespace app\index\controller;
- use think\facade\Db;
- use think\worker\Server;
- use Workerman\Lib\Timer;
- //define('HEARTBEAT_TIME', 20); // 心跳间隔
- class Worker extends Server
- {
- protected $socket = 'websocket://0.0.0.0:2345/wss'; //设置地址
- protected $online_count = 0; //统计在线人数
- /* 此处为实现SSL证书wss连接
- protected $context = [
- 'ssl' => [
- 'local_cert' => 'C:/Apache24/ssl/api_hilo8_com.crt', //证书文件的存放路径(请改成自己的路径)
- 'local_pk' => 'C:/Apache24/ssl/api_hilo8_com.key', //证书私钥的存放路径(请改成自己的路径)
- 'verify_peer' => false,
- //'allow_self_signed' => true, //如果是自签名证书需要开启此选项
- ],
- ];
- protected $option = [
- 'transport' => 'ssl', //设置transport开启ssl,启用wss://
- ];
- */
- /**
- * 收到信息
- * @param $connection
- * @param $data
- */
- public function onMessage($connection, $data)
- {
- $origin = json_decode($data, true);
- switch ($origin['type']) {
- //绑定用户
- case 'login':
- $connection->uid = $origin['uid'];
- $connection->uname = $origin['uname'];
- $connection->login_time = time();
- $this->online_count++;
- $this->onlineUid();
- $send_content = [
- 'type' => 'text',
- 'content' => '用户(' . $connection->uid . '=' . $connection->uname . ')已上线!' . $connection->login_time
- ];
- $this->sendMessage($send_content);
- break;
- //收到消息,并回复
- case 'text':
- $user = [];
- $user['from_uid'] = $origin['from_uid']; // 发送方用户uid
- $user['from_uname'] = $origin['from_uname']; //发送方用户名称
- $user['to_uid'] = $origin['to_uid']; // 接收方用户uid
- $user['to_uname'] = $origin['to_uname']; //接收方用户名称
- $content = $origin['content']; // 需要发送到对方的内容
- $send_content = [
- 'type' => 'text',
- 'user' => $user,
- 'content' => $content
- ];
- $this->sendMessage($send_content, $origin['to_uid']);
- break;
- }
- echo ("收到消息:{$data}\n");
- }
- /**
- * 当连接建立时触发的回调函数
- * @param $connection
- */
- public function onConnect($connection)
- {
- $link_time = time();
- echo "连接时间:{$link_time}\n";
- $send_content = [
- 'type' => 'connect',
- 'content' => '连接成功:' . $link_time
- ];
- $connection->send(json_encode($send_content, JSON_UNESCAPED_UNICODE));
- }
- /**
- * 当连接断开时触发的回调函数
- * @param $connection
- */
- public function onClose($connection)
- {
- if (isset($connection->uid)) {
- echo "连接关闭 " . $connection->uid . "=" . $connection->uname . " (time:" . time() . ")\n";
- $this->online_count--;
- $send_content = [
- 'type' => 'text',
- 'content' => '用户(' . $connection->uid . '=' . $connection->uname . ')已下线!' . time()
- ];
- $this->sendMessage($send_content);
- }
- }
- /**
- * 当客户端的连接上发生错误时触发
- * @param $connection
- * @param $code
- * @param $msg
- */
- public function onError($connection, $code, $msg)
- {
- echo "error $code $msg\n";
- }
- /**
- * 每个进程启动
- * @param $worker
- */
- public function onWorkerStart($worker)
- {
- Timer::add(10, function () use ($worker) {
- if ($this->online_count > 0) {
- $this->onlineUid();
- }
- });
- }
- //统计在线用户
- private function onlineUid()
- {
- $online_uid = $online_data = [];
- foreach ($this->worker->connections as $connection) {
- if (isset($connection->uid)) {
- //array_push($online_uid, $connection->uid . '=' . $connection->uname);
- $online_data[] = ['uid' => $connection->uid, 'uname' => $connection->uname];
- }
- }
- $send_content = [
- 'type' => 'online',
- 'count' => $this->online_count,
- 'content' => $online_data
- ];
- $this->sendMessage($send_content);
- }
- //发送消息
- private function sendMessage($content = [], $uid = 0)
- {
- $message = json_encode($content, JSON_UNESCAPED_UNICODE);
- if (is_numeric($uid) && $uid > 0) {
- //单发消息
- foreach ($this->worker->connections as $connection) {
- if (isset($connection->uid) && $connection->uid == $uid) {
- $connection->send($message);
- }
- }
- } else {
- //群发消息
- foreach ($this->worker->connections as $connection) {
- $connection->send($message);
- }
- }
- }
- }
说明:虽然上面可以实现SSL证书wss连接,但不建议这样做,建议以服务器代理方式实现。
四、启动WebSocket,命令:php think worker:server
五、客户端连接,代码如下:
LANG-JSwww.hilo8.com
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8">
- <meta name="renderer" content="webkit">
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>WebSocket聊天</title>
- <script type="text/javascript" src="https://www.hilo8.com/js/jquery.js"></script>
- <style>
- html,
- body {
- height: 100%;
- margin: 0;
- padding: 0;
- }
- .container {
- position: relative;
- height: 100%;
- overflow: auto;
- }
- .online-box {
- position: absolute;
- width: 150px;
- height: 100%;
- background-color: antiquewhite;
- }
- .online-box h4 {
- text-align: center;
- }
- .online-box ul li {
- cursor: pointer;
- padding: 5px 0px;
- font-size: 14px;
- }
- .online-box ul li:hover {
- color: #c00;
- }
- .main-box {
- margin-left: 150px;
- }
- #msg {
- color: #999;
- font-size: 12px;
- background-color: #f6f6f6;
- padding: 10px;
- }
- #msg p {
- margin: 10px 0px 0px 0px;
- }
- #msg p span {
- border: 1px solid #ddd;
- border-radius: 4px;
- padding: 3px 5px;
- display: block;
- font-size: 14px;
- color: #333;
- background-color: #fff;
- float: left;
- }
- #msg p span.self {
- background-color: #090;
- color: #fff;
- float: right;
- }
- #msg font{font-size: 12px; color: #999; display: block;}
- .clear {
- clear: both;
- *zoom: 1
- }
- .clear:after {
- content: '\20';
- clear: both;
- *zoom: 1;
- display: block;
- height: 0
- }
- </style>
- </head>
- <body>
- <div class="container">
- <div class="online-box">
- <h4>在线用户列表</h4>
- <ul>
- <li data-user="0,所有人">所有人</li>
- </ul>
- </div>
- <div class="main-box">
- <h1>WebSocket示例</h1>
- <p>
- <input type="text" id="uname" placeholder="请输入您的名称" />
- <button type="button">连接</button>
- <button type="button">关闭</button>
- </p>
- <p>
- 接收人: <span id="to-uname-span">所有人</span><br>
- <input type="hidden" id="to-uid" value="0"><input type="hidden" id="to-uname" value="所有人">
- <input type="text" id="content" placeholder="请输入要发送的内容" />
- <button>发送</button>
- </p>
- <hr>
- <div id="msg" class="clear"></div>
- </div>
- </div>
- <script>
- $(function(){
- var socket;
- var uid = Math.floor(Math.random() * 10000) + 1; //随机生成用户id号
- var uname = ''; //用户名称
- /* 连接状态 */
- var state = 0;
- var sockState = function () {
- let status = ['未连接', '连接成功,可通信', '正在关闭', '连接已关闭或无法打开'];
- return status[state];
- }
- //显示服务器返回消息
- var showMsg = function (message) {
- $("#msg").append('<p class="clear">' + message + '</p>');
- }
- /* 打开连接事件 */
- $("button:eq(0)").click(function () {
- uname = $('#uname').val();
- if (uname == '') {
- alert('请输入您的名称再连接');
- return;
- }
- try {
- /* 连接 */
- socket = new WebSocket("ws://api.shiyunkj.com:2345/wss");
- /* 绑定事件 */
- /* 监听连接状态 */
- socket.onopen = function () {
- state = socket.readyState;
- socket.send(JSON.stringify({ type: 'login', uid: uid, uname: uname }));
- };
- /* 接收消息 */
- socket.onmessage = function (e) {
- let res = JSON.parse(e.data);
- switch (res.type) {
- case 'online':
- let online_count = $('.online-box ul li').length - 1;
- let lis = '<li data-user="0,所有人">所有人</li>';
- if (online_count != res.count) {
- $.each(res.content, function (key, val) {
- lis += '<li data-user="' + val.uid + ',' + val.uname + '">' + val.uname + '</li>';
- })
- $('.online-box ul').html(lis);
- }
- break;
- case 'connect':
- case 'text':
- let str = '';
- if (res.user != undefined) {
- let user = res.user.from_uname || '';
- if (user != '') { str = '<font>'+user+'</font>'; }
- }
- showMsg(str+"<span>" + res.content + '</span>');
- break;
- default:
- showMsg("接收信息出错...");
- }
- //showMsg("<br>" + res.content);
- };
- /* 关闭连接 */
- socket.onclose = function () {
- state = socket.readyState;
- showMsg("连接已关闭或无法连接服务器..." + state);
- };
- } catch (exception) {
- showMsg("有错误发生...");
- }
- });
- /* 发送数据事件 */
- $("button:eq(2)").click(function () {
- if (state != 1) {
- alert(sockState());
- return;
- } else if ($("#content").val() == "") {
- alert("请输入发送内容!");
- return;
- }
- try {
- showMsg('<span class="self">' + $("#content").val() + '</span>');
- let data = { type: "text", from_uid: uid, from_uname: uname, to_uid: $("#to-uid").val(), to_uname: $("#to-uname").val(), content: $("#content").val() };
- socket.send(JSON.stringify(data));
- } catch (exception) {
- showMsg("发送数据出错...");
- }
- /* 清空文本框 */
- $("#content").val("");
- });
- /* 断开连接 */
- $("button:eq(1)").click(function () {
- try {
- showMsg("关闭连接...");
- socket.close();
- } catch (exception) {
- alert(sockState());
- }
- });
- //选择用户
- $('.online-box ul').on('click', 'li', function () {
- let arr = $(this).data('user').split(',');
- $('#to-uid').val(arr[0]);
- $('#to-uname').val(arr[1]);
- $('#to-uname-span').html(arr[1]);
- });
- });
- </script>
- </body>
- </html>
可以多人在线聊天,如下图演示:
上一篇:TP6 生成Qrcode二维码和Barcode条形码的方法
讨论数量:0