Рубрики
Uncategorized

Практикует весь [чат]

Автор оригинала: David Wong.

Вам следует попрактиковаться после того, как вы поймете концепцию, или вы станете гигантским ребенком

Если есть какой-либо урожай, пожалуйста Добавьте маленькую звездочку Если не будет урожая Оппозиция Никакой помощи Отчет Санлиан

  • Хранилище кода
  • Практика свул [чат-комната]
  • Опыт работы в Интернете

Подготовка

  • Вам нужно сначала понять все в целом [1], и понять основные принципы использования websocket на стороне сервера
  • Клиент JS websocket прост в использовании

Воспользуйся

Command line 1
php src/websocket/run.php
Command line 2
cd public && php -S localhost:8000
#Client, open more to check the effect
Visit http: // localhost: 8000/

WebSocket

Официальный пример

$server = new swoole_websocket_server("0.0.0.0", 9501);
$server->on('open', function (swoole_websocket_server $server, $request) {
        echo "server: handshake success with fd{$request->fd}\n";
    });
$server->on('message', function (swoole_websocket_server $server, $frame) {
        echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
        $server->push($frame->fd, "this is server");
    });
$server->on('close', function ($ser, $fd) {
        echo "client {$fd} closed\n";
    });
$server->on('request', function (swoole_http_request $request, swoole_http_response $response) {
        Global $server; // call external server
        //$server - > connections traverses the FD of all websocket connected users and pushes to all users
        foreach ($server->connections as $fd) {
            $server->push($fd, $request->get['message']);
        }
    });
$server->start();

Подробное объяснение:

  • Свул? Веб-карман? Сервер наследуется от swool? HTTP? Сервер

    • Если установлен обратный вызов onrequest, сервер websocket также может одновременно выступать в качестве HTTP-сервера
    • Обратный вызов onrequest не установлен, сервер websocket вернет страницу с ошибкой HTTP 400 после получения HTTP – запроса
    • Если вы хотите запустить push всех веб-сайтов, получив HTTP, вам нужно обратить внимание на область действия. Для ориентированного на процесс, пожалуйста, используйте global для ссылки на сервер swool websocket. Для объектно-ориентированного вы можете установить сервер swool websocket в качестве свойства участника
  • функция onOpen(swoole_websocket_server $svr , swoole_http_request $req );

    • Эта функция вызывается обратно, когда клиент websocket устанавливает соединение с сервером и завершает рукопожатие.
    • $req-это объект HTTP-запроса, который содержит информацию о запросе на рукопожатие, отправленную клиентом
    • В функции события onopen вы можете вызвать push для отправки данных клиенту или закрыть, чтобы закрыть соединение
    • Обратный вызов события onopen является необязательным
  • функция onMessage(swoole_websocket_server $сервер , swoole_websocket_frame $кадр )

    • Эта функция вызывается обратно, когда сервер получает фрейм данных от клиента.
    • $кадр-это свул? Веб-карман? Объект фрейма, содержащий информацию о фрейме данных, отправленную клиентом
    • Обратный вызов Onmessage Должен быть установлен , сервер не запустится без настройки
    • Кадр ping, отправленный клиентом, не будет срабатывать при сообщении, и базовый уровень автоматически ответит на пакет pong
  • Свул? Веб-карман? Свойство рамки

    • $рамка->fd , идентификатор сокета клиента, используя $server->push Push-данные
    • $frame->данные , содержимое данных, может быть текстовым содержимым или двоичными данными, можно судить по значению кода операции
    • $фрейм->код операции Для определения типа кода операции websocket, пожалуйста, обратитесь к стандартному документу протокола websocket
    • $frame->готово Указывает, завершен ли фрейм данных или нет. Запрос websocket может быть отправлен в нескольких кадрах данных (нижний уровень реализовал автоматическое объединение кадров данных, теперь вам не нужно беспокоиться о неполном полученном кадре данных).

Пример сервера чата

Структура каталогов:

  • конфиг

    • конфиг
  • src

    • websocket

      • websocket
      • websocket
      • Websocketserver.php версия таблицы памяти
      • Wsredisserver.php версия redis

Websocketserver.php версия таблицы памяти

createTable();
        //Instantiation configuration
        $this->config = Config::getInstance();
    }

    public function run()
    {
        $this->server = new \swoole_websocket_server(
            $this->config['socket']['host'],
            $this->config['socket']['port']
        );

        $this->server->on('open', [$this, 'open']);
        $this->server->on('message', [$this, 'message']);
        $this->server->on('close', [$this, 'close']);

        $this->server->start();
    }

    public function open(\swoole_websocket_server $server, \swoole_http_request $request)
    {
        $user = [
            'fd' => $request->fd,
            'name' => $this->config['socket']['name'][array_rand($this->config['socket']['name'])] . $request->fd,
            'avatar' => $this->config['socket']['avatar'][array_rand($this->config['socket']['avatar'])]
        ];
        //Put in memory table
        $this->table->set($request->fd, $user);

        $server->push($request->fd, json_encode(
                array_merge(['user' => $user], ['all' => $this->allUser()], ['type' => 'openSuccess'])
            )
        );
    }

    private function allUser()
    {
        $users = [];
        foreach ($this->table as $row) {
            $users[] = $row;
        }
        return $users;
    }

    public function message(\swoole_websocket_server $server, \swoole_websocket_frame $frame)
    {
        $this->pushMessage($server, $frame->data, 'message', $frame->fd);
    }

    /**
     *Push message
     *
     * @param \swoole_websocket_server $server
     * @param string $message
     * @param string $type
     * @param int $fd
     */
    private function pushMessage(\swoole_websocket_server $server, string $message, string $type, int $fd)
    {
        $message = htmlspecialchars($message);
        $datetime = date('Y-m-d H:i:s', time());
        $user = $this->table->get($fd);

        foreach ($this->table as $item) {
            //Don't send it by yourself
            if ($item['fd'] == $fd) {
                continue;
            }

            $server->push($item['fd'], json_encode([
                'type' => $type,
                'message' => $message,
                'datetime' => $datetime,
                'user' => $user
            ]));
        }
    }

    /**
     *When the client is closed
     *
     * @param \swoole_websocket_server $server
     * @param int $fd
     */
    public function close(\swoole_websocket_server $server, int $fd)
    {
        $user = $this->table->get($fd);
        $this - > pushmessage ($server, "{$user ['name ']} leave the chat room",'close', $FD);
        $this->table->del($fd);
    }

    /**
     *Create memory table
     */
    private function createTable()
    {
        $this->table = new \swoole_table(1024);
        $this->table->column('fd', \swoole_table::TYPE_INT);
        $this->table->column('name', \swoole_table::TYPE_STRING, 255);
        $this->table->column('avatar', \swoole_table::TYPE_STRING, 255);
        $this->table->create();
    }
}

Wsredisserver.php версия redis

config = Config::getInstance();
        // redis
        $this->initRedis();
        //Initialization, mainly because the server itself will not clear redis
        foreach ($this->allUser() as $item) {
            $this->client->hdel("{$this->key}:{$item['fd']}", ['fd', 'name', 'avatar']);
        }
    }

    public function run()
    {
        $this->server = new \swoole_websocket_server(
            $this->config['socket']['host'],
            $this->config['socket']['port']
        );

        $this->server->on('open', [$this, 'open']);
        $this->server->on('message', [$this, 'message']);
        $this->server->on('close', [$this, 'close']);

        $this->server->start();
    }

    public function open(\swoole_websocket_server $server, \swoole_http_request $request)
    {
        $user = [
            'fd' => $request->fd,
            'name' => $this->config['socket']['name'][array_rand($this->config['socket']['name'])] . $request->fd,
            'avatar' => $this->config['socket']['avatar'][array_rand($this->config['socket']['avatar'])]
        ];
        //Put it in redis
        $this->client->hmset("{$this->key}:{$user['fd']}", $user);

        //Push to everyone, including yourself
        foreach ($this->allUser() as $item) {
            $server->push($item['fd'], json_encode([
                'user' => $user,
                'all' => $this->allUser(),
                'type' => 'openSuccess'
            ]));
        }
    }

    private function allUser()
    {
        $users = [];
        $keys = $this->client->keys("{$this->key}:*");
        //All keys
        foreach ($keys as $k => $item) {
            $users[$k]['fd'] = $this->client->hget($item, 'fd');
            $users[$k]['name'] = $this->client->hget($item, 'name');
            $users[$k]['avatar'] = $this->client->hget($item, 'avatar');
        }
        return $users;
    }

    public function message(\swoole_websocket_server $server, \swoole_websocket_frame $frame)
    {
        $this->pushMessage($server, $frame->data, 'message', $frame->fd);
    }

    /**
     *Push message
     *
     * @param \swoole_websocket_server $server
     * @param string $message
     * @param string $type
     * @param int $fd
     */
    private function pushMessage(\swoole_websocket_server $server, string $message, string $type, int $fd)
    {
        $message = htmlspecialchars($message);
        $datetime = date('Y-m-d H:i:s', time());
        $user['fd'] = $this->client->hget("{$this->key}:{$fd}", 'fd');
        $user['name'] = $this->client->hget("{$this->key}:{$fd}", 'name');
        $user['avatar'] = $this->client->hget("{$this->key}:{$fd}", 'avatar');

        foreach ($this->allUser() as $item) {
            //Don't send it by yourself
            if ($item['fd'] == $fd) {
                continue;
            }

            $is_push = $server->push($item['fd'], json_encode([
                'type' => $type,
                'message' => $message,
                'datetime' => $datetime,
                'user' => $user
            ]));
            //Delete failed push
            if (!$is_push) {
                $this->client->hdel("{$this->key}:{$item['fd']}", ['fd', 'name', 'avatar']);
            }
        }
    }

    /**
     *When the client is closed
     *
     * @param \swoole_websocket_server $server
     * @param int $fd
     */
    public function close(\swoole_websocket_server $server, int $fd)
    {
        $user['fd'] = $this->client->hget("{$this->key}:{$fd}", 'fd');
        $user['name'] = $this->client->hget("{$this->key}:{$fd}", 'name');
        $user['avatar'] = $this->client->hget("{$this->key}:{$fd}", 'avatar');
        $this - > pushmessage ($server, "{$user ['name ']} leave the chat room",'close', $FD);
        $this->client->hdel("{$this->key}:{$fd}", ['fd', 'name', 'avatar']);
    }

    /**
     *Initialize redis
     */
    private function initRedis()
    {
        $this->client = new Client([
            'scheme' => $this->config['socket']['redis']['scheme'],
            'host' => $this->config['socket']['redis']['host'],
            'port' => $this->config['socket']['redis']['port'],
        ]);
    }
}

Wsredisserver.php версия redis

path = __DIR__ . '/../../config/';
    }

    //Singleton mode
    public static function getInstance()
    {
        if (!self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function offsetSet($offset, $value)
    {
        // castration
    }

    public function offsetGet($offset)
    {
        if (empty($this->config)) {
            $this->config[$offset] = require $this->path . $offset . ".php";
        }
        return $this->config[$offset];
    }

    public function offsetExists($offset)
    {
        return isset($this->config[$offset]);
    }

    public function offsetUnset($offset)
    {
        // castration
    }

    //Prohibit cloning
    final private function __clone(){}
}

config/socket.php

 '0.0.0.0',
    'port' => 9501,

    'redis' => [
        'scheme' => 'tcp',
        'host' => '0.0.0.0',
        'port' => 6380
    ],

    'avatar' => [
        './images/avatar/1.jpg',
        './images/avatar/2.jpg',
        './images/avatar/3.jpg',
        './images/avatar/4.jpg',
        './images/avatar/5.jpg',
        './images/avatar/6.jpg'
    ],

    'name' => [
        'Kobe',
        'Curie',
        'KD',
        'KG',
        'Jordan',
        'Duncan',
        'Green',
        'Thompson',
        'igodara',
        'Maddie',
        'Iverson',
        'Kai Wan Yi',
        'Paul'
    ]
];

config/socket.php

run();

резюме

Полный пример: комната чата

После обучения я обнаружил, что так называемый чат в моей жизни точно такой же. Конечно, это всего лишь простая демонстрация, и многие функции не реализованы. Если вы хотите учиться дальше, вы можете перейти на GitHub, чтобы найти полный проект для углубленного изучения

Справочные ресурсы

  • свул
  • Простая комната чата, реализованная с помощью PHP + swool