前提是你服务器必须安装了Swoole扩展,没有安装请移步官网:https://wiki.swoole.com/

在安装这个扩展之后,确保php有安装swoole扩展  php.ini 查找 extension=swoole.so,也可以去看 phpinfo 查看是否成功安装swoole扩展

由于每次要命令行启动swoole服务器,关闭shell窗口就关闭了swoole服务,我们自定义一条Artisan Command

生成swoole demo:

  php artisan make:command SwooleDemo

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;

class SwooleDemo extends Command

{

// 命令名称
protected $signature = 'swoole:demo';
// 命令说明
protected $description = '这是关于swoole websocket的一个测试demo';
// swoole websocket服务
private static $server = null;

public function __construct()
{
  parent::__construct();
}

// 入口
public function handle()
{
  $this->redis = Redis::connection('websocket');
  $server = self::getWebSocketServer();
  $server->on('open',[$this,'onOpen']);
  $server->on('message', [$this, 'onMessage']);
  $server->on('close', [$this, 'onClose']);
  $server->on('request', [$this, 'onRequest']);
  $this->line("swoole服务启动成功 ...");
  $server->start();
}

// 获取服务
public static function getWebSocketServer()
{
  if (!(self::$server instanceof \swoole_websocket_server)) {
    self::setWebSocketServer();
  }
  return self::$server;
}
// 服务处始设置
protected static function setWebSocketServer():void
{
  self::$server = new \swoole_websocket_server("0.0.0.0", 9502);
  self::$server->set([
    'worker_num' => 1,
    heartbeat_check_interval' => 60, // 60秒检测一次
    'heartbeat_idle_time' => 121, // 121秒没活动的
  ]);
}

// 打开swoole websocket服务回调代码
public function onOpen($server, $request)
{
  if ($this->checkAccess($server, $request)) {\
    self::$server->push($request->fd,"打开swoole服务成功!");\
  }
}
// 给swoole websocket 发送消息回调代码
public function onMessage($server, $frame)
{

}
// http请求swoole websocket 回调代码
public function onRequest($request,$response)
{

}
// websocket 关闭回调代码
public function onClose($serv,$fd)
{
  $this->line("客户端 {$fd} 关闭");
}
// 校验客户端连接的合法性,无效的连接不允许连接
public function checkAccess($server, $request):bool
{
  $bRes = true;
  if (!isset($request->get) || !isset($request->get['token'])) {
    self::$server->close($request->fd);
    $this->line("接口验证字段不全");
    $bRes = false;
  } else if ($request->get['token'] !== "123456") {
    $this->line("接口验证错误");
    $bRes = false;
  }
  return $bRes;
}
// 启动websocket服务
public function start()
{
  self::$server->start();
}


}

编写websoket js代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>swoole测试</title>
<meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"></head>
<body>
  <h1>这是一个测试</h1></body>
  <script>

    var ws; //websocket实例
    var lockReconnect = false; //避免重复连接
    var wsUrl = 'ws://{{$_SERVER["HTTP_HOST"]}}:9502?page=home&token=123456';

    function initEventHandle() {
      ws.onclose = function() {
        reconnect(wsUrl);
      };
      ws.onerror = function() {
        reconnect(wsUrl);
      };
      ws.onopen = function() {
        //心跳检测重置
        heartCheck.reset().start();
      };
      ws.onmessage = function(event) {
        //如果获取到消息,心跳检测重置
        //拿到任何消息都说明当前连接是正常的
        var data = JSON.parse(event.data);
        heartCheck.reset().start();
      }
    }
    createWebSocket(wsUrl);
    /**
     * 创建链接
     * @param url
     */
    function createWebSocket(url) {
      try {
        ws = new WebSocket(url);
        initEventHandle();
      } catch(e) {
        reconnect(url);
      }
    }
    function reconnect(url) {
      if (lockReconnect) return;
      lockReconnect = true;
      //没连接上会一直重连,设置延迟避免请求过多
      setTimeout(function() {
        createWebSocket(url);
        lockReconnect = false;
      },2000);
    }
    //心跳检测
    var heartCheck = {
      timeout: 60000,
      //60秒
      timeoutObj: null,
      serverTimeoutObj: null,
      reset: function() {
        clearTimeout(this.timeoutObj);
        clearTimeout(this.serverTimeoutObj);
        return this;
      },
      start: function() {
        var self = this;
        this.timeoutObj = setTimeout(function() {
        //这里发送一个心跳,后端收到后,返回一个心跳消息,
        //onmessage拿到返回的心跳就说明连接正常
        ws.send("heartbeat");
        self.serverTimeoutObj = setTimeout(function() { //如果超过一定时间还没重置,说明后端主动断开了
          ws.close(); //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
        },self.timeout);
      },this.timeout);
    },
    header: function(url) {
      window.location.href = url
    }

  }

</script>

</html>

运行中出现的问题:

出错原因是因为LNMP 禁用了部分存在危险的PHP函数,我们要修改php.ini配置文件:找到 disable_functions 一行 去除 putenv

重载php配置,再次启动swoole-http服务就欧了