swoole-websocket聊天室

服务端:
server.php

<?php

/**
 * Date: 2020/8/28
 * Time: 3:28 下午
 */
class chat
{
    const HOST = '0.0.0.0';//ip地址 0.0.0.0代表接受所有ip的访问
    const PART = 81;//端口号
    private $server = null;//单例存放websocket_server对象

    public function __construct()
    {
        //实例化swoole_websocket_server并存储在我们Chat类中的属性上,达到单例的设计
        $this->server = new swoole_websocket_server(self::HOST, self::PART);
        // 建立连接后进行握手。WebSocket 服务器会自动进行 handshake 握手的过程,如果用户希望自己进行握手处理,可以设置 onHandShake 事件回调函数。
//        $this->server->on('handshake', [$this, 'onHandshake']);
        //监听连接事件
        $this->server->on('open', [$this, 'onOpen']);
        //监听接收消息事件
        $this->server->on('message', [$this, 'onMessage']);
        //监听关闭事件
        $this->server->on('close', [$this, 'onClose']);
        //设置允许访问静态文件
        $this->server->set([
            'worker_num'      => 2, //开启2个worker进程
            'max_request'     => 4, //每个worker进程 max_request设置为4次
            'task_worker_num' => 4, //开启4个task进程
            'dispatch_mode'   => 4, //数据包分发策略 - IP分配
            'daemonize'       => false, //守护进程(true/false)

            'document_root'         => '/swoole/chat2',//这里传入客户端文件存放地址
            'enable_static_handler' => true//允许访问静态文件
        ]);
        //异步防止阻塞当前进程   必须先设置 task_worker_num 必须设置 Server 的 onTask 和 onFinish 事件回调函数。
        $this->server->on("Task", [$this, 'onTask']);
        //task 进程中完成时, task 进程会通过 finish() 方法将任务处理的结果发送给 worker 进程。
        $this->server->on("Finish", [$this, 'onFinish']);
        //开启服务
        $this->server->start();
    }

    /**
     *
     * @param \Swoole\Http\Request $request
     * @param \Swoole\Http\Response $response
     *
     * @return bool
     */
    public function onHandshake($request, $response)
    {
        // websocket握手连接算法验证
        $secWebSocketKey = $request->header['sec-websocket-key'];
        $patten = '#^[+/0-9A-Za-z]{21}[AQgw]==$#';
        if (0 === preg_match($patten, $secWebSocketKey) || 16 !== strlen(base64_decode($secWebSocketKey))) {
            $response->end();
            return false;
        }
        echo $request->header['sec-websocket-key'];
        $key = base64_encode(
            sha1(
                $request->header['sec-websocket-key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
                true
            )
        );

        $headers = [
            'Upgrade' => 'websocket',
            'Connection' => 'Upgrade',
            'Sec-WebSocket-Accept' => $key,
            'Sec-WebSocket-Version' => '13',
        ];

        // WebSocket connection to 'ws://127.0.0.1:9502/'
        // failed: Error during WebSocket handshake:
        // Response must not include 'Sec-WebSocket-Protocol' header if not present in request: websocket
        if (isset($request->header['sec-websocket-protocol'])) {
            $headers['Sec-WebSocket-Protocol'] = $request->header['sec-websocket-protocol'];
        }

        foreach ($headers as $key => $val) {
            $response->header($key, $val);
        }

        $response->status(101);
        $response->end();
    }

    /**
     * 连接成功回调函数---如果系统调用了handshake函数,就不会触发这个
     *
     * @param Swoole\WebSocket\Server $server
     * @param Swoole\Http\Request $request
     *
     * $request 是一个 HTTP 请求对象,包含了客户端发来的握手请求信息
     * onOpen 事件函数中可以调用 push 向客户端发送数据或者调用 close 关闭连接
     * onOpen 事件回调是可选的
     */
    public function onOpen($server,$request)
    {
        $this->server->task([
            'type' => 'online',
            'fd' => $request->fd
        ]);
//        foreach ($server->connections as $fd) {
//            if ($request->fd !== $fd) {
//                $server->push($fd, json_encode(['no' => $request->fd, 'msg' => '上线了,快来聊天吧!']));
//            }
//        }
    }

    /**
     * 接收到信息的回调函数
     *
     * @param Swoole\WebSocket\Server $server
     * @param Swoole\WebSocket\Frame $frame
     * 属性	说明
       $frame->fd	客户端的 socket id,使用 $server->push 推送数据时需要用到
       $frame->data	数据内容,可以是文本内容也可以是二进制数据,可以通过 opcode 的值来判断
       $frame->opcode	WebSocket 的 OpCode 类型,可以参考 WebSocket 协议标准文档
       $frame->finish	表示数据帧是否完整,一个 WebSocket 请求可能会分成多个数据帧进行发送(底层已经实现了自动合并数据帧,现在不用担心接收到的数据帧不完整)
     */
    public function onMessage($server, $frame)
    {
        echo $frame->fd . '来了,说:' . $frame->data . PHP_EOL;//打印到我们终端
        if($frame->data==10){
            $server->push($frame->fd, json_encode(['no' => $frame->fd, 'msg' => '不要发"10",谢谢!']));
            $this->server->disconnect($frame->fd,403,'不要发"10",谢谢!');
        }
        $this->server->task([
            'type' => 'message',
            'msg' => $frame->data,
            'fd' =>  $frame->fd
        ]);
//        foreach ($server->connections as $fd) {
//            $server->push($fd, json_encode(['no' => $frame->fd, 'msg' => $frame->data]));
//        }
    }

    /**
     * 异步task
     *
     * @param Swoole\WebSocket\Server $server
     * @param $task_id //从 0-42 亿的整数,在当前进程内是唯一的
     * @param $from_id
     * @param $data
     */
    public function onTask($server, $task_id, $from_id, $data)
    {
        echo "#{$server->worker_id} onTask: [PID={$server->worker_pid}]: task_id={$task_id}: from_id={$from_id}".PHP_EOL;
        $msg = '';
        switch ($data['type']) {
            case 'online':
                $msg = '我上线了,快来聊天吧!';
                break;
            case 'message':
                $msg = $data['msg'];
                break;
            default:
                $msg = '这是神马操作!';
                break;
        }
        foreach ($server->connections as $fd) {
            $connectionInfo = $server->connection_info($fd);
            if ($connectionInfo['websocket_status'] == 3) {
                $server->push($fd, json_encode(['no' => $data['fd'], 'msg' => $msg])); //长度最大不得超过2M
            }
        }
        $server->finish($data);
    }

    /**
     * 此回调函数在 worker 进程被调用,当 worker 进程投递的任务在 task 进程中完成时,
     * task 进程会通过 Swoole\Server->finish() 方法将任务处理的结果发送给 worker 进程。
     * @param Swoole\WebSocket\Server $server
     * @param $task_id
     * @param $data
     */
    public function onFinish($server,$task_id, $data)
    {

    }
    /**
     * 断开连接回调函数
     *
     * @param Swoole\WebSocket\Server $server
     * @param int $fdUser
     */
    public function onClose($server, $fdUser)
    {
//        var_dump($this->server->exist(10));
        foreach ($server->connections as $fd) {
            if($fd!==$fdUser){
                $server->push($fd, json_encode(['no' => $fdUser, 'msg' => '我走啦!']));
            }
        }
    }
}

$obj = new Chat();

客户端
client.html

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>swoole-websocket聊天室</title>
    <script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<textarea class="log" style="width: 100%; height: 500px;">
=======swoole-websocket聊天室======
</textarea>
<input type="button" value="连接" onClick="link()">
<input type="button" value="断开" onClick="dis()">
<input type="text" id="text">
<input type="button" value="发送" onClick="send()">
<script>
    function link(){
        var url='ws://127.0.0.1:81';
        socket=new WebSocket(url);
        socket.onopen=function(){log1('连接成功')}
        socket.onmessage=function(msg){log(msg.data);console.log(msg);}
        socket.onclose=function(){log1('断开连接')}
    }

    function dis(){
        socket.close();
        socket=null;
    }

    function log1(var1) {
        $('.log').append(var1+'\r\n');
    }
    function log(var1){
        var  v=$.parseJSON(var1)
        $('.log').append('用户'+v['no']+'说:'+v['msg']+'\r\n');
    }

    function send(){
        var text=$('#text').val();
        socket.send(text);
    }

    function send2(){
        var json = JSON.stringify({'type':'php','msg':$('#text2').attr('value')})
        socket.send(json);

    }
</script>
</body>
</html>

启动

php server.php
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值