《 swooleThinkphp 》 WebSocket PHP 即时通讯开发 【二】

WebSocket PHP 即时通讯开发



PHP 在之前的某一段时间里是被认为无法处理好协议层面的,但是随着Workerman,Swoole 以及目前风头正上的 MEEPOPS 的出现,彻底打破了这一局面,让很多人发现原来 PHP 能做的事越来越多。


接下来本章将详细介绍如何用 swoole_websocket_server 和 ThinkPHP5 的命令行来建立 websocket 服务器。


本章没有使用think-swoole Composer 包。

创建 ThinkPHP5 自定义命令行

在 ThinkPHP5 中推荐使用命令行工具来管理运行不需要外部访问的程序,如 http 服务器启动程序,websocket 服务器启动程序,crontab(计划任务/定时器)等


1.创建命令行类

创建application/console/WebSocket.php文件

<?php

namespace app\Console;

use think\console\Command;
use think\console\Input;
use think\console\Output;

class WebSocket extends Command
{
    // 命令行配置函数
    protected function configure()
    {
        // setName 设置命令行名称
        // setDescription 设置命令行描述
        $this->setName('websocket:start')->setDescription('Start Web Socket Server!');
    }
    // 设置命令返回信息
    protected function execute(Input $input, Output $output)
    {
        $output->writeln("WebSocket: Start.\n");
    }
}

2.修改配置文件

文件所在 application/command.php


<?php

return [
    'app\console\WebSocket',
];

这时在项目根目录输入命令行就可以看到已经配置好的命令行类及描述

$ > php think


Delevin、博客



编写 Web Socket 逻辑代码

接下来我们就可以正式编写 web socket 服务器的代码了,Swoole 帮我们内置了 web socket 服务器支持,通过几行 PHP 代码就可以写出一个异步非阻塞多进程的 web scoket 服务器。

在application/console/WebSocket.php文件中继续编写代码

<?php

namespace app\Console;

use think\console\Command;
use think\console\Input;
use think\console\Output;

class WebSocket extends Command
{
    // Server 实例
    protected $server;
    protected function configure()
    {
        $this->setName('websocket:start')->setDescription('Start Web Socket Server!');
    }
    protected function execute(Input $input, Output $output)
    {
        // 监听所有地址,监听 10000 端口
        $this->server = new \swoole_websocket_server('0.0.0.0', 10000);
        
        // 设置 server 运行前各项参数
        // 调试的时候把守护进程关闭,部署到生产环境时再把注释取消
        // $this->server->set([
        //     'daemonize' => true,
        // ]);
        
        // 设置回调函数
        $this->server->on('Open', [$this, 'onOpen']);
        $this->server->on('Message', [$this, 'onMessage']);
        $this->server->on('Close', [$this, 'onClose']);
        
        $this->server->start();
        // $output->writeln("WebSocket: Start.\n");
    }
    // 建立连接时回调函数
    public function onOpen(\swoole_websocket_server $server, \swoole_http_request $request)
    {
        echo "server: handshake success with fd{$request->fd}\n";
    }
    // 收到数据时回调函数
    public function onMessage(\swoole_websocket_server $server, \swoole_websocket_frame $frame)
    {
        echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
        $server->push($frame->fd, "this is server");
    }
    // 连接关闭时回调函数
    public function onClose($server, $fd)
    {
        echo "client {$fd} closed\n";
    }
}

在命令行输入php think websocket:start启动 web socket 服务器

接下来我们使用 JavaScript 代码来测试 Web Socket 服务器是否正常运行,推荐使用 Chrome 来进行调试


<script>
    var  websocket = new WebSocket('ws://localhost:10000'); 
    websocket.onopen = function (evt) { onOpen(evt) }; 
    websocket.onclose = function (evt) { onClose(evt) }; 
    websocket.onmessage = function (evt) { onMessage(evt) }; 
    websocket.onerror = function (evt) { onError(evt) }; 
     
    function onOpen(evt) {
        console.log("Connected to WebSocket server."); 
    } 
    function onClose(evt) { 
        console.log("Disconnected"); 
    }
    function onMessage(evt) { 
        console.log('Retrieved data from server: ' + evt.data); 
    } 
    function onError(evt) { 
        console.log('Error occured: ' + evt.data); 
    }
</script>

打开 Chrome 浏览器的调试工具,切换到 Console 选项卡下看到如下图结果,表示 web socket 连接成功




同时服务器端命令行下应该看到如下回执消息

server: handshake success with fd1