1.安装
composer安装TP5.1,安装swoole,安装workerman
composer create-project topthink/think=5.1.* tp5
composer require topthink/think-swoole=2.0.*
composer require topthink/think-worker=2.0.*
2.手册
Workerman:workerman 手册
GatewayWorker:http://doc2.workerman.net/642185
Swoole:swoole简介 · swoole手册 · 看云
3.代码
workerman:文件 /config/worker_server.php
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
use think\facade\Env;
use think\helper\Time;
use Workerman\Lib\Timer;
// +----------------------------------------------------------------------
// | Workerman设置 仅对 php think worker:server 指令有效
// +----------------------------------------------------------------------
return [
// 扩展自身需要的配置
'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
'host' => '0.0.0.0', // 监听地址
'port' => 2345, // 监听端口
'socket' => '', // 完整监听地址
'context' => [], // socket 上下文选项
'worker_class' => '', // 自定义Workerman服务类名 支持数组定义多个服务
// 支持workerman的所有配置参数
'name' => 'thinkphp',
'count' => 4,
'daemonize' => false,
'pidFile' => Env::get('runtime_path') . 'worker.pid',
// 支持事件回调
// onWorkerStart
'onWorkerStart' => function ($worker) {
echo "onWorkerStart\n";
// var_dump($worker);echo "\n";
},
// onWorkerReload
'onWorkerReload' => function ($worker) {
},
// onConnect
'onConnect' => function ($connection) {
$data = array(
"commandid"=>"2000",
"uid"=>$connection->id
);
$connection->send(json_encode($data));
},
// onMessage
'onMessage' => function ($connection, $data) {
$message_data = json_decode($data, true);
$data = $message_data;
switch ($data['commandid']) {
case '3000':
foreach($connection->worker->connections as $con){
$con->send(json_encode($data));
}
break;
case '2000':
$logata = array(
"uid" => $connection->id,
"commandid" => "2001"
);
foreach($connection->worker->connections as $con){
$con->send(json_encode($logata));
}
break;
default:
# code...
break;
}
},
// onClose
'onClose' => function ($connection) {
echo "onClose\n";
},
// onError
'onError' => function ($connection, $code, $msg) {
echo "error [ $code ] $msg\n";
},
];
swoole:文件 /config/swoole_server.php
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
use think\facade\Env;
// +----------------------------------------------------------------------
// | Swoole设置 php think swoole:server 命令行下有效
// +----------------------------------------------------------------------
return [
// 扩展自身配置
'host' => '0.0.0.0', // 监听地址
'port' => 9508, // 监听端口
'type' => 'socket', // 服务类型 支持 socket http server
'mode' => '', // 运行模式 默认为SWOOLE_PROCESS
'sock_type' => '', // sock type 默认为SWOOLE_SOCK_TCP
'swoole_class' => '', // 自定义服务类名称
// 可以支持swoole的所有配置参数
'daemonize' => false,
'pid_file' => Env::get('runtime_path') . 'swoole_server.pid',
'log_file' => Env::get('runtime_path') . 'swoole_server.log',
// 事件回调定义
'onOpen' => function ($server, $request) {
$data = array(
"commandid"=>"2000",
"uid"=>$request->fd
);
$server->push($request->fd, json_encode($data));
// echo "server: handshake success with fd{$request->fd}\n";
},
'onMessage' => function ($server, $frame) {
$message_data = json_decode($frame->data, true);
$data = $message_data;
// $task_id = $server->task($data, 0);
// $task_id = $server->task($frame->fd);
switch ($data['commandid']) {
case '3000':
foreach($server->connections as $fd){
$server->push($fd, json_encode($data));
}
break;
case '2000':
$logata = array(
"uid" => $frame->fd,
"commandid" => "2001"
);
foreach($server->connections as $fd){
$server->push($fd, json_encode($logata));
}
break;
default:
# code...
break;
}
// echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
},
'onRequest' => function ($request, $response) {
$response->end("<h1>Hello Swoole. #" . rand(1000, 9999) . "</h1>");
},
'onClose' => function ($ser, $fd) {
// echo "client {$fd} closed\n";
},
'onWorkerStart' => function ($worker) {
echo "onWorkerStart\n";
},
];
GatewayWorker:文件 /config/gateway_worker.php
定义类文件 /application/gatewayclass/Events.php
<?php
namespace app\gatewayclass;
use GatewayWorker\Lib\Gateway;
class Events
{
public static function onWorkerStart($businessWorker){
}
public static function onConnect($client_id){
$data = array(
"commandid"=>"2000",
"uid"=>$client_id
);
Gateway::sendToClient($client_id, json_encode($data));
Gateway::joinGroup($client_id, 1);
}
public static function onWebSocketConnect($client_id, $data){
}
public static function onMessage($client_id, $message){
$message_data = json_decode($message, true);
$data = $message_data;
switch ($data['commandid']) {
case '1000':
Gateway::bindUid($client_id, $message_data['uid']);
case '3000':
Gateway::sendToGroup(1,json_encode($data));
break;
case '2000':
$logata = array(
"uid" => $client_id,
"commandid" => "2001"
);
Gateway::sendToGroup(1,json_encode($logata));
break;
default:
# code...
break;
}
}
public static function onClose($client_id){
}
}
三种方式都也可以在自定义命令里面扩展或者自定义服务类名称,
workerman:worker_class
gatewayworker:businessWorker['eventHandler']
swoole:swoole_class
前端:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1"> -->
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">
<title>SUNAR TEST</title>
<script src="/static/js/jquery-1.11.1.min.js"></script>
<style>
.chattxt{
width:80%;
height:500px;
border: 1px #000 solid;
}
</style>
</head>
<body>
<div class="chattxt">
</div>
<div>
<input id="uid" value="1">
<input id="chat">
<button id="chatbtn">提交</button>
</div>
<script>
ws = new WebSocket("ws://192.168.42.128:8282");
ws.onopen = function() {
ws.send("uid:1");
};
ws.onclose = function() {
ws.send("uid:2");
};
ws.onmessage = function(e) {
if(e.data!="null"){
var uid = $("#uid").val();
var str = e.data;
var data = JSON.parse(str);
console.log(data)
switch (data.commandid) {
case "3000":
if(data.uid==uid){
var str = "<p style='text-align: right;'>" + data.uid + ":" + data.msg + "</p>";
}else{
var str = "<p style='text-align: left;'>" + data.uid + ":" + data.msg + "</p>";
}
$(".chattxt").append(str);
break;
case "2000":
$("#uid").val(data.uid);
var json = {
uid:uid,
commandid:"2000"
};
var jsonstr = JSON.stringify(json);
ws.send(jsonstr);
break;
case "2001":
var str = "<p style='text-align: center;'>用户" + data.uid + ",上线</p>";
$(".chattxt").append(str);
break;
default:
break;
}
}
};
$("#chatbtn").click(function(){
var uid = $("#uid").val();
var con = $("#chat").val();
var json = {
uid:uid,
commandid:"3000",
msg:con
};
var jsonstr = JSON.stringify(json);
ws.send(jsonstr);
})
</script>
</body>
代码分享,有缘人自行下载。