先上链接;http://chenshuixing.com:8812/chat/chat.html
功能比较简单,可以一对一聊天,也可以群聊。下面是服务器代码,加载了tp5.1框架
<?php
/**
* ws 优化 基础类库
* User: singwa
* Date: 18/3/2
* Time: 上午12:34
*/
class Ws {
CONST HOST = "0.0.0.0"; // 0.0.0.0表示监听所有地址
CONST PORT = 8812; // 监听端口 8811作为HTTP服务端口
public $ws = null;
public function __construct() {
$this->ws = new swoole_websocket_server(self::HOST, self::PORT);
// 同时保留http服务的配置
$this->ws->set(
[
'worker_num' => 5,
'task_worker_num' => 1,
'enable_static_handler' => true,
'document_root' => '/usr/local/nginx/html/zhibo/public/static', //静态资源目录
]
);
$this->ws->on("start", [$this, 'onStart']);
$this->ws->on("open", [$this, 'onOpen']);
$this->ws->on("message", [$this, 'onMessage']);
$this->ws->on('WorkerStart',[$this,"onWorkerStart"]);
$this->ws->on("request",[$this,'onRequest']);
$this->ws->on("task", [$this, 'onTask']);
$this->ws->on("finish", [$this, 'onFinish']);
$this->ws->on("close", [$this, 'onClose']);
$this->ws->start();
}
public function onStart($server)
{
// onStart调用时修改主进程名称,方便重启脚本能够找到对应的pid
}
/**
* 监听websocket连接事件
* @param $ws
* @param $request
*/
public function onOpen($ws, $request) {
$client_list = \app\common\lib\Predis::getInstance()->sMembers(config('live.client_ids_key'));
\app\common\lib\Predis::getInstance()->sAdd(config('live.client_ids_key'), $request->fd);
\app\common\lib\Predis::getInstance()->set(config('live.client_ids_key').$request->fd, $request->get['name']);
$list = [];
if (!empty($client_list)) {
foreach ($client_list as $value) {
$row = [];
$row['id'] = $value;
$row['name'] = \app\common\lib\Predis::getInstance()->get(config('live.client_ids_key').$value);
$list[] = $row;
}
}
// 给当前链接的客户播报现在所有的在线客户
$ws->push($request->fd,json_encode(['action'=>'online_list','data'=>$list]));
// 给所有在线客户播报当前新连接的客户
if (!empty($client_list)) {
foreach ($client_list as $value) {
if ($request->fd != $value) {
$ws->push($value,json_encode(['action'=>'online_list','data'=>[['id'=>$request->fd,'name'=>$request->get['name']]]]));
}
}
}
}
/**
* 此事件在Worker进程/Task进程启动时发生
* @param [type] $serv [description]
* @param [type] $worker_id [description]
* @return [type] [description]
*/
public function onWorkerStart($serv, $worker_id)
{
// 加载php的核心文件进来
define('APP_PATH', __DIR__ . '/../../application/');
require __DIR__ . '/../../thinkphp/base.php';
think\Container::get('app', [APP_PATH]) ->run()->send();
}
/**
* 监听ws消息事件
* @param $ws
* @param $frame 包含客户端fd,data
*/
public function onMessage($ws, $frame) {
$rec_msg = json_decode($frame->data);
var_dump($rec_msg);
$send_info = ['action'=>'say','data'=>['name'=>$rec_msg->name,'content'=>$rec_msg->content,'time'=>$rec_msg->time] ];
if ($rec_msg->to_client) {
// 发送给对象和自己
$this->ws->push($rec_msg->to_client, json_encode($send_info));
$this->ws->push($frame->fd, json_encode($send_info));
} else {
// 广播给所有人
$client_list = \app\common\lib\Predis::getInstance()->sMembers(config('live.client_ids_key'));
foreach ($client_list as $value) {
$this->ws->push($value, json_encode($send_info));
}
}
}
/**
* @param $serv
* @param $taskId
* @param $workerId
* @param $data
*/
public function onTask($serv, $taskId, $workerId, $data) {
print_r($data);
// 耗时场景 10s
sleep(10);
return "on task finish"; // 告诉worker
}
/**
* @param $serv
* @param $taskId
* @param $data
*/
public function onFinish($serv, $taskId, $data) {
echo "taskId:{$taskId}\n";
echo "finish-data-sucess:{$data}\n";
}
/**
* ws断开
* @param $ws
* @param $fd
*/
public function onClose($ws, $fd) {
\app\common\lib\Predis::getInstance()->sRem(config('live.client_ids_key'), $fd);
\app\common\lib\Predis::getInstance()->del(config('live.client_ids_key').$fd);
$client_list = \app\common\lib\Predis::getInstance()->sMembers(config('live.client_ids_key'));
// 为线上客户播报该客户下线
if(!empty($client_list)) {
$data = ['action'=>'offline', 'data'=>['id'=>$fd]];
foreach ($client_list as $key => $value) {
$ws->push($value,json_encode($data));
}
}
}
/**
* http请求
* @param [type] $request [description]
* @param [type] $response [description]
* @return [type] [description]
*/
public function onRequest($request,$response)
{
$_GET = array();
if (!empty($request->get)) {
foreach ($request->get as $key => $value) {
$_GET[$key] = $value;
}
}
$_POST = array();
if (!empty($request->post)) {
foreach ($request->post as $key => $value) {
$_POST[$key] = $value;
}
}
// 每次post接口的时候,加入对象
$_POST['http_server'] = $this->ws;
$_FILES = array();
if (!empty($request->files)) {
foreach ($request->files as $key => $value) {
$_FILES[strtoupper($key)] = $value;
}
}
$_SERVER = array();
if (!empty($request->server)) {
foreach ($request->server as $key => $value) {
$_SERVER[strtoupper($key)] = $value;
}
}
if (!empty($request->header)) {
foreach ($request->header as $key => $value) {
$_SERVER[strtoupper($key)] = $value;
}
}
// 2. thinkphp执行应用
ob_start();
try{
think\Container::get('app', [APP_PATH])
->run()
->send();
}catch(\Exception $e){
echo 'Caught exception: ', $e->getMessage(), "\n";
}
$res = ob_get_contents();
ob_end_clean();
$response->end($res);
}
}
$obj = new Ws();