Maison  >  Article  >  développement back-end  >  La série PHP+Socket implémente la salle de discussion Websocket

La série PHP+Socket implémente la salle de discussion Websocket

藏色散人
藏色散人avant
2023-02-02 16:39:514141parcourir

Cet article vous apporte des connaissances pertinentes sur php+socket. Il présente principalement comment utiliser le socket natif php pour implémenter une simple salle de discussion Web ? Les amis intéressés peuvent jeter un œil ci-dessous. J'espère que cela sera utile à tout le monde. Le socket natif OPhp réalise la salle de discussion WebSocket

Avant-propos

Cet article réalise l'utilisation du socket natif PHP pour réaliser une salle de discussion Web simple, et le code final se trouve au bas de l'article.

À tout le moins, cela devrait être le dernier article de cette série d'articles. Quand j'ai écrit cette série d'articles, je pensais que ce serait une chose très simple, mais après avoir écrit ces quelques articles, j'ai presque lu le code de Workerman, alors ne soyez jamais trop vaniteux, vous devez l'essayer vous-même, de préférence l'écrire, pour prouver que vous comprenez vraiment quelque chose

Introduction à websocket

Le protocole webSocket est un protocole de communication réseau Il est né en 2008. et est devenu un standard international en 2011. Le standard

RFC6455

définit son standard de communication et est désormais pris en charge par tous les navigateurs. webSocket est un protocole de communication en duplex intégral sur une seule connexion TCP que HTML5 a commencé à fournir. Le serveur peut envoyer activement des messages au client, et le client peut également envoyer activement des messages au serveur. webSocket stipule la spécification d'un protocole de communication. Grâce au mécanisme de prise de contact, une connexion de type TCP peut être établie entre le client (navigateur) et le serveur (serveur Web), facilitant ainsi la communication CS.

Pourquoi avons-nous besoin de websocket

Le protocole HTTP est un protocole de couche application unidirectionnel, sans état et sans connexion. Il adopte le modèle Request=>Response. Les requêtes de communication ne peuvent être initiées que par le client, et le serveur répond à la requête. Ce modèle de communication présente un inconvénient : il est impossible pour le serveur d'envoyer de manière proactive. messages au client. Le client lance un message. Les capacités de concurrence des requêtes HTTP traditionnelles sont obtenues en initiant plusieurs connexions TCP pour accéder au serveur en même temps. Websocket nous permet d'émettre simultanément plusieurs requêtes sur une connexion ws. Autrement dit, une fois la requête A envoyée, la réponse A a été envoyée. pas encore arrivé. Vous pouvez continuer à émettre des demandes B. En raison de la fonctionnalité de démarrage lent de TCP et de la perte de connexion de la connexion elle-même, cette fonctionnalité du protocole websocket a considérablement amélioré l'efficacité.

Comparaison http vs websocket请求 => 响应 模型,通信请求仅能由客户端发起,服务端对请求做出应答处理,这种通信模型有一个弊端:无法实现服务端主动向客户端发起消息。传统的 HTTP 请求,其并发能力都是依赖同时发起多个 TCP 连接访问服务器实现的而 websocket 则允许我们在一条 ws 连接上同时并发多个请求,即在 A 请求发出后 A 响应还未到达,就可以继续发出 B 请求。由于 TCP 的慢启动特性,以及连接本身的握手损耗,都使得 websocket 协议的这一特性有很大的效率提升。

La série PHP+Socket implémente la salle de discussion Websocket

特点

  • 建立在 TCP 协议之上,服务端的实现相对比较容易

  • 与 HTTP 协议有良好的兼容性,默认端口也是 80 和 443,并且握手阶段采用 HTTP 协议,因此握手时不容易被屏蔽,能通过各种 HTTP 代理服务器。

  • 数据格式比较轻量,性能开销小,通信高效。

  • 可以发送文本,也可以发送二进制数据。

  • 没有同源限制,客户端可以与任意服务器进行通信。

  • 协议标识符是 ws(如果加密则为 wss),服务地址就是 URL。

PHP实现websocket

客户端与服务端握手

websocket 协议在连接前需要握手[^2],通常握手方式有以下几种方式

  • 基于 flash 的握手协议(不建议)

  • 基于 md5 加密方式的握手协议

    较早的握手方法,有两个 key,使用 md5 加密

  • 基于 sha1 加密方式的握手协议

    当前主要的握手协议,本文将以此协议为主

    • 获取客户端上报的 Sec-WebSocket-key

    • 拼接 key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11

    • 对字符串做 SHA1 计算,再把得到的结果通过 base64

      Fonctionnalités
      • est construit sur le protocole TCP, et la mise en œuvre du serveur est relativement simple

    • a une bonne compatibilité avec le HTTP protocole, par défaut Les ports sont également 80 et 443, et le protocole HTTP est utilisé dans la phase de prise de contact, il n'est donc pas facilement bloqué pendant la prise de contact et peut passer par divers serveurs proxy HTTP.

  • Le format de données est relativement léger, a une faible surcharge de performances et une communication efficace.

  • Vous pouvez envoyer du texte ou des données binaires.

  • Il n'y a pas de restriction de même origine, le client peut communiquer avec n'importe quel serveur.
  • L'identifiant du protocole est ws (ou wss si crypté), et l'adresse du service est l'URL.

    PHP implémente websocketHandshake client et serveur

    🎜Le protocole websocket nécessite une handshake avant la connexion [^2], il existe généralement les méthodes de handshake suivantes🎜
    • 🎜basées sur le protocole flash Handshake (non recommandé)🎜🎜
    • 🎜Protocole de prise de contact basé sur la méthode de cryptage md5🎜🎜Méthode de prise de contact antérieure, avec deux clés, utilisant le cryptage md5🎜🎜
    • 🎜Protocole de prise de contact basé sur la méthode de cryptage sha1🎜🎜 Le protocole de prise de contact principal actuel , cet article se concentrera sur ce protocole🎜
      • 🎜Récupérez la Sec-WebSocket-key rapportée par le client 🎜🎜
      • 🎜Splice key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11🎜🎜
      • 🎜Faites SHA1 à la chaîne Calculer, puis crypter le résultat via base64, et enfin le renvoyer au client 🎜🎜🎜🎜🎜🎜Les informations de la demande du client sont les suivantes : 🎜
        GET /chat HTTP/1.1Host: server.example.com
        Upgrade: websocket
        Connection: Upgrade
        Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==Origin: http://example.com
        Sec-WebSocket-Protocol: chat, superchat
        Sec-WebSocket-Version: 13
        🎜Le client doit renvoyer les données suivantes : 🎜
        HTTP/1.1 101 Switching Protocols
        Upgrade: websocket
        Sec-WebSocket-Version: 13Connection: Upgrade
        Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
        🎜us Implémenté via PHP selon ce protocole : 🎜
        <?php
        
        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, true);
        socket_bind($socket, 0, 8888);
        socket_listen($socket);
        
        while (true) {
            $conn_sock = socket_accept($socket);
            $request = socket_read($conn_sock, 102400);
        
            $new_key = getShaKey($request);
        
            $response = "HTTP/1.1 101 Switching Protocols\r\n";
            $response .= "Upgrade: websocket\r\n";
            $response .= "Sec-WebSocket-Version: 13\r\n";
            $response .= "Connection: Upgrade\r\n";
            $response .= "Sec-WebSocket-Accept: {$new_key}\r\n\r\n";
        
            socket_write($conn_sock, $response);
        }
        
        function getShaKey($request)
        {
            // 获取 Sec-WebSocket-key
            preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $request, $match);
        
            // 拼接 key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11
            $new_key = trim($match[1]) . &#39;258EAFA5-E914-47DA-95CA-C5AB0DC85B11&#39;;
        
            // 对字符串做 `SHA1` 计算,再把得到的结果通过 `base64` 加密
            return base64_encode(sha1($new_key, true));
        }
        🎜Les explications de la syntaxe associée peuvent être trouvées dans les 🎜articles précédents🎜, cet article ne la présentera pas en détail. 🎜🎜Utilisez les tests front-end, ouvrez l'une de nos consoles de navigateur et entrez le contenu suivant. L'état prêt de l'objet websocket renvoyé est 1, ce qui signifie que la poignée de main est réussie. Il s'agit du contenu front-end. en détail. Pour plus de détails, veuillez vous référer au 🎜Tutoriel Rookie🎜 : 🎜
        console.log(new WebSocket('ws://192.162.2.166:8888'));
        // 运行后返回:
        WebSocket {
            binaryType: "blob"
            bufferedAmount: 0
            extensions: ""
            onclose: null
            onerror: null
            onmessage: null
            onopen: null
            protocol: ""
            readyState: 1
            url: "ws://192.162.2.166:8888/"}
        🎜🎜🎜🎜Envoi et réception de données🎜🎜

        使用 websocket 协议传输协议需要遵循特定的格式规范,详情请参考 datatracker.ietf.org/doc/html/rfc6...

        La série PHP+Socket implémente la salle de discussion Websocket

        为了方便,这里直接贴出加解密代码,以下代码借鉴与 workermansrc/Protocols/Websocket.php 文件:

        // 解码客户端发送的消息
        function decode($buffer)
        {
            $len = \ord($buffer[1]) & 127;
            if ($len === 126) {
                $masks = \substr($buffer, 4, 4);
                $data = \substr($buffer, 8);
            } else {
                if ($len === 127) {
                    $masks = \substr($buffer, 10, 4);
                    $data = \substr($buffer, 14);
                } else {
                    $masks = \substr($buffer, 2, 4);
                    $data = \substr($buffer, 6);
                }
            }
            $dataLength = \strlen($data);
            $masks = \str_repeat($masks, \floor($dataLength / 4)) . \substr($masks, 0, $dataLength % 4);
            return $data ^ $masks;
        }
        
        // 编码发送给客户端的消息
        function encode($buffer)
        {
            if (!is_scalar($buffer)) {
                throw new \Exception("You can&#39;t send(" . \gettype($buffer) . ") to client, you need to convert it to a string. ");
            }
            $len = \strlen($buffer);
        
            $first_byte = "\x81";
        
            if ($len <= 125) {
                $encode_buffer = $first_byte . \chr($len) . $buffer;
            } else {
                if ($len <= 65535) {
                    $encode_buffer = $first_byte . \chr(126) . \pack("n", $len) . $buffer;
                } else {
                    $encode_buffer = $first_byte . \chr(127) . \pack("xxxxN", $len) . $buffer;
                }
            }
        
            return $encode_buffer;
        }

        我们修改刚才 客户端与服务端握手 阶段的代码,修改后全代码全文如下,该段代码实现了将客户端发送的消息转为大写后返回给客户端(当然只是为了演示):

        <?php
        
        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, true);
        socket_bind($socket, 0, 8888);
        socket_listen($socket);
        
        while (true) {
            $conn_sock = socket_accept($socket);
            $request = socket_read($conn_sock, 102400);
        
            $new_key = getShaKey($request);
        
            $response = "HTTP/1.1 101 Switching Protocols\r\n";
            $response .= "Upgrade: websocket\r\n";
            $response .= "Sec-WebSocket-Version: 13\r\n";
            $response .= "Connection: Upgrade\r\n";
            $response .= "Sec-WebSocket-Accept: {$new_key}\r\n\r\n";
        
            // 发送握手数据
            socket_write($conn_sock, $response);
        
            // 新增内容,获取客户端发送的消息并转为大写还给客户端
            $msg = socket_read($conn_sock, 102400);
            socket_write($conn_sock, encode(strtoupper(decode($msg))));
        }
        
        function getShaKey($request)
        {
            // 获取 Sec-WebSocket-key
            preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $request, $match);
        
            // 拼接 key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11
            $new_key = trim($match[1]) . &#39;258EAFA5-E914-47DA-95CA-C5AB0DC85B11&#39;;
        
            // 对字符串做 `SHA1` 计算,再把得到的结果通过 `base64` 加密
            return base64_encode(sha1($new_key, true));
        }
        
        function decode($buffer)
        {
            $len = \ord($buffer[1]) & 127;
            if ($len === 126) {
                $masks = \substr($buffer, 4, 4);
                $data = \substr($buffer, 8);
            } else {
                if ($len === 127) {
                    $masks = \substr($buffer, 10, 4);
                    $data = \substr($buffer, 14);
                } else {
                    $masks = \substr($buffer, 2, 4);
                    $data = \substr($buffer, 6);
                }
            }
            $dataLength = \strlen($data);
            $masks = \str_repeat($masks, \floor($dataLength / 4)) . \substr($masks, 0, $dataLength % 4);
            return $data ^ $masks;
        }
        
        function encode($buffer)
        {
            if (!is_scalar($buffer)) {
                throw new \Exception("You can&#39;t send(" . \gettype($buffer) . ") to client, you need to convert it to a string. ");
            }
            $len = \strlen($buffer);
        
            $first_byte = "\x81";
        
            if ($len <= 125) {
                $encode_buffer = $first_byte . \chr($len) . $buffer;
            } else {
                if ($len <= 65535) {
                    $encode_buffer = $first_byte . \chr(126) . \pack("n", $len) . $buffer;
                } else {
                    $encode_buffer = $first_byte . \chr(127) . \pack("xxxxN", $len) . $buffer;
                }
            }
        
            return $encode_buffer;
        }

        使用 在线测试工具 进行测试,可以看到消息已经可以正常发送接收,接下来的文章将继续优化代码,实现简易聊天室,敬请关注:

        La série PHP+Socket implémente la salle de discussion Websocket

        实现web聊天室

        我们紧接着上文的代码继续优化,以实现简易的web聊天室

        多路复用

        其实就是加一下 socket_select() 函数 La série PHP+Socket implémente la salle de discussion Websocket ,本文就不写原理与语法了,详情可参考 之前的文章,以下代码修改自前文 La série PHP+Socket implémente la salle de discussion Websocket

        ...
        
        socket_listen($socket);
        
        +$sockets[] = $socket;
        +$user = [];
        while (true) {
        +   $tmp_sockets = $sockets;
        +   socket_select($tmp_sockets, $write, $except, null);
        
        +   foreach ($tmp_sockets as $sock) {
        +       if ($sock == $socket) {
        +           $sockets[] = socket_accept($socket);
        +           $user[] = [&#39;socket&#39; => $socket, &#39;handshake&#39; => false];
        +       } else {
        +           $curr_user = $user[array_search($sock, $user)];
        +           if ($curr_user[&#39;handshake&#39;]) { // 已握手
        +               $msg = socket_read($sock, 102400);
        +               echo &#39;客户端发来消息&#39; . decode($msg);
        +               socket_write($sock, encode(&#39;这是来自服务端的消息&#39;));
        +           } else {
        +               // 握手
        +           }
        +       }
        +   }
        
        -   $conn_sock = socket_accept($socket);
        -   $request = socket_read($conn_sock, 102400);
        
        ...

        实现聊天室

        最终成果演示

        La série PHP+Socket implémente la salle de discussion Websocket

        我们将上述代码改造成类,并在类变量储存用户信息,添加消息处理等逻辑,最后贴出代码,建议保存下来自己尝试一下,也许会有全新的认知,后端代码:

        <?php
        
        new WebSocket();
        
        class Websocket
        {
            /**
             * @var resource
             */
            protected $socket;
        
            /**
             * @var array 用户列表
             */
            protected $user = [];
        
            /**
             * @var array 存放所有 socket 资源
             */
            protected $socket_list = [];
        
            public function __construct()
            {
                $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
                socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, true);
                socket_bind($this->socket, 0, 8888);
                socket_listen($this->socket);
        
                // 将 socket 资源放入 socket_list
                $this->socket_list[] = $this->socket;
        
                while (true) {
                    $tmp_sockets = $this->socket_list;
                    socket_select($tmp_sockets, $write, $except, null);
        
                    foreach ($tmp_sockets as $sock) {
                        if ($sock == $this->socket) {
                            $conn_sock = socket_accept($sock);
                            $this->socket_list[] = $conn_sock;
                            $this->user[] = [&#39;socket&#39; => $conn_sock, &#39;handshake&#39; => false, &#39;name&#39; => &#39;无名氏&#39;];
                        } else {
                            $request = socket_read($sock, 102400);
                            $k = $this->getUserIndex($sock);
        
                            if (!$request) {
                                continue;
                            }
        
                            // 用户端断开连接
                            if ((\ord($request[0]) & 0xf) == 0x8) {
                                $this->close($k);
                                continue;
                            }
        
                            if (!$this->user[$k][&#39;handshake&#39;]) {
                                // 握手
                                $this->handshake($k, $request);
                            } else {
                                // 已握手
                                $this->send($k, $request);
                            }
                        }
                    }
                }
            }
        
            /**
             * 关闭连接
             *
             * @param $k
             */
            protected function close($k)
            {
                $u_name = $this->user[$k][&#39;name&#39;] ?? &#39;无名氏&#39;;
                socket_close($this->user[$k][&#39;socket&#39;]);
                $socket_key = array_search($this->user[$k][&#39;socket&#39;], $this->socket_list);
                unset($this->socket_list[$socket_key]);
                unset($this->user[$k]);
        
                $user = [];
                foreach ($this->user as $v) {
                    $user[] = $v[&#39;name&#39;];
                }
                $res = [
                    &#39;type&#39; => &#39;close&#39;,
                    &#39;users&#39; => $user,
                    &#39;msg&#39; => $u_name . &#39;已退出&#39;,
                    &#39;time&#39; => date(&#39;Y-m-d H:i:s&#39;)
                ];
                $this->sendAllUser($res);
            }
        
            /**
             * 获取用户索引
             *
             * @param $socket
             * @return int|string
             */
            protected function getUserIndex($socket)
            {
                foreach ($this->user as $k => $v) {
                    if ($v[&#39;socket&#39;] == $socket) {
                        return $k;
                    }
                }
            }
        
            /**
             * 握手
             * @param $k
             * @param $request
             */
            protected function handshake($k, $request)
            {
                preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $request, $match);
                $key = base64_encode(sha1($match[1] . &#39;258EAFA5-E914-47DA-95CA-C5AB0DC85B11&#39;, true));
        
                $response = "HTTP/1.1 101 Switching Protocols\r\n";
                $response .= "Upgrade: websocket\r\n";
                $response .= "Connection: Upgrade\r\n";
                $response .= "Sec-WebSocket-Accept: {$key}\r\n\r\n";
                socket_write($this->user[$k][&#39;socket&#39;], $response);
                $this->user[$k][&#39;handshake&#39;] = true;
            }
        
            /**
             * 接收并处理消息
             *
             * @param $k
             * @param $msg
             */
            public function send($k, $msg)
            {
                $msg = $this->decode($msg);
                $msg = json_decode($msg, true);
        
                if (!isset($msg[&#39;type&#39;])) {
                    return;
                }
        
                switch ($msg[&#39;type&#39;]) {
                    case &#39;login&#39;: // 登录
                        $this->user[$k][&#39;name&#39;] = $msg[&#39;name&#39;] ?? &#39;无名氏&#39;;
                        $users = [];
                        foreach ($this->user as $v) {
                            $users[] = $v[&#39;name&#39;];
                        }
                        $res = [
                            &#39;type&#39; => &#39;login&#39;,
                            &#39;name&#39; => $this->user[$k][&#39;name&#39;],
                            &#39;msg&#39; => $this->user[$k][&#39;name&#39;] . &#39;: login success&#39;,
                            &#39;users&#39; => $users,
                        ];
                        $this->sendAllUser($res);
                        break;
                    case &#39;message&#39;: // 接收并发送消息
                        $res = [
                            &#39;type&#39; => &#39;message&#39;,
                            &#39;name&#39; => $this->user[$k][&#39;name&#39;] ?? &#39;无名氏&#39;,
                            &#39;msg&#39; => $msg[&#39;msg&#39;],
                            &#39;time&#39; => date(&#39;H:i:s&#39;),
                        ];
                        $this->sendAllUser($res);
                        break;
                }
            }
        
            /**
             * 发送给所有人
             *
             */
            protected function sendAllUser($msg)
            {
                if (is_array($msg)) {
                    $msg = json_encode($msg);
                }
        
                $msg = $this->encode($msg);
        
                foreach ($this->user as $k => $v) {
                    socket_write($v[&#39;socket&#39;], $msg, strlen($msg));
                }
            }
        
            /**
             * 解码
             *
             * @param $buffer
             * @return string
             */
            protected function decode($buffer)
            {
                $len = \ord($buffer[1]) & 127;
                if ($len === 126) {
                    $masks = \substr($buffer, 4, 4);
                    $data = \substr($buffer, 8);
                } else {
                    if ($len === 127) {
                        $masks = \substr($buffer, 10, 4);
                        $data = \substr($buffer, 14);
                    } else {
                        $masks = \substr($buffer, 2, 4);
                        $data = \substr($buffer, 6);
                    }
                }
                $dataLength = \strlen($data);
                $masks = \str_repeat($masks, \floor($dataLength / 4)) . \substr($masks, 0, $dataLength % 4);
                return $data ^ $masks;
            }
        
            protected function encode($buffer)
            {
                if (!is_scalar($buffer)) {
                    throw new \Exception("You can&#39;t send(" . \gettype($buffer) . ") to client, you need to convert it to a string. ");
                }
                $len = \strlen($buffer);
        
                $first_byte = "\x81";
        
                if ($len <= 125) {
                    $encode_buffer = $first_byte . \chr($len) . $buffer;
                } else {
                    if ($len <= 65535) {
                        $encode_buffer = $first_byte . \chr(126) . \pack("n", $len) . $buffer;
                    } else {
                        $encode_buffer = $first_byte . \chr(127) . \pack("xxxxN", $len) . $buffer;
                    }
                }
        
                return $encode_buffer;
            }
        }

        前端代码如下(前端内容不在本文讨论范围之内,具体可参考 菜鸟教程):

        <!doctype html>
        <html>
        <head>
            <meta charset="UTF-8">
            <meta name="viewport"
                  content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Document</title>
        </head>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            h3 {
                display: flex;
                justify-content: center;
                margin: 30px auto;
            }
            .but-box {
                border-radius: 5px;
                display: flex;
                justify-content: center;
                align-items: center;
                margin-top: 10px;
            }
            #box {
                display: flex;
                margin: 5px auto;
                border-radius: 5px;
                border: 1px #ccc solid;
                height: 400px;
                width: 700px;
                overflow-y: auto;
                overflow-x: hidden;
                position: relative;
            }
            #msg-box {
                width: 480px;
                margin-right: 111px;
                height: 100%;
                overflow-y: auto;
                overflow-x: hidden;
            }
            #user-box {
                width: 110px;
                overflow-y: auto;
                overflow-x: hidden;
                float: left;
                border-left: 1px #ccc solid;
                height: 100%;
                background-color: #F1F1F1;
            }
            button {
                float: right;
                width: 80px;
                height: 35px;
                font-size: 18px;
            }
            input {
                width: 100%;
                height: 30px;
                padding: 2px;
                line-height: 20px;
                outline: none;
                border: solid 1px #CCC;
            }
            .but-box p {
                margin-right: 160px;
            }
        </style>
        <body>
        
        <h3>这是一个php socket实现的web聊天室</h3>
        
        <div id="box">
            <div id="msg-box"></div>
            <div id="user-box"></div>
        </div>
        
        <div>
        
            <p><textarea cols="60" rows="3" style="resize:none;pedding: 10px"    id="content"> </textarea></p>
            <button id="send">发送</button>
        </div>
        <script src="https://cdn.bootcss.com/jquery/2.2.1/jquery.min.js"></script>
        <script>
            let ws = new WebSocket(&#39;ws://124.222.85.67:8888&#39;);
        
            ws.onopen = function (event) {
                console.log(&#39;连接成功&#39;);
        
                var name = prompt(&#39;请输入用户名:&#39;);
        
                ws.send(JSON.stringify({
                    type: &#39;login&#39;,
                    name: name
                }));
        
                if (!name) {
                    alert(&#39;好你个坏蛋,竟然没有输入用户名&#39;);
                }
            };
            ws.onmessage = function (event) {
                let data = JSON.parse(event.data);
                console.log(data);
        
                switch (data.type) {
                    case &#39;close&#39;:
                    case &#39;login&#39;:
                        $("#user-box").html(&#39;&#39;);
                        data.users.forEach(function (item) {
                            $("#user-box").append(`<p style="color: grey;">${item}</p>`);
                        });
                        if (data.msg) {
                            $("#msg-box").append(`<p style="color: grey;">${data.msg}</p>`);
                        }
                        break;
                    case &#39;message&#39;:
                        $("#msg-box").append(`<p><span style="color: #0A89FF">${data.time}</span><span style="color: red">${data.name}</span>${data.msg}</p>`);
                        break;
                }
            };
        
            ws.onclose = function (event) {
                alert(&#39;连接关闭&#39;);
            };
        
            document.onkeydown = function (event) {
                if (event.keyCode == 13) {
                    send();
                }
            }
        
            $("#send").click(function () {
                send();
            });
        
            function send() {
                let content = $("#content").val();
                $("#content").val(&#39;&#39;);
                if (!content) {
                    return;
                }
                ws.send(JSON.stringify({
                    type: &#39;message&#39;,
                    msg: content
                }));
            }
        </script>
        </body>
        </html>

        [^1]:是通讯传输的一个术语。 通信允许数据在两个方向上同时传输,它在能力上相当于两个单工通信方式的结合
        [^2]:  为了建立 websocket 连接,需要通过浏览器发出请求,之后服务器进行回应,这个过程通常称为“握手”(Handshaking)

        推荐学习:《PHP视频教程》                                            

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer