首页后端开发其他后端知识PHP实现WebSocket怎样做,有哪些要点

PHP实现WebSocket怎样做,有哪些要点

时间2024-03-25 08:20:03发布访客分类其他后端知识浏览1491
导读:这篇文章给大家介绍了“PHP实现WebSocket怎样做,有哪些要点”的相关知识,讲解详细,步骤过程清晰,对大家进一步学习和理解“PHP实现WebSocket怎样做,有哪些要点”有一定的帮助,希望大家阅读完这篇文章能有所收获。下面就请大家跟...
这篇文章给大家介绍了“PHP实现WebSocket怎样做,有哪些要点”的相关知识,讲解详细,步骤过程清晰,对大家进一步学习和理解“PHP实现WebSocket怎样做,有哪些要点”有一定的帮助,希望大家阅读完这篇文章能有所收获。下面就请大家跟着小编的思路一起来学习一下吧。

WebSocket 是什么?

摘抄网上的一些解释:

WebSocket 协议是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。

WebSocket 通信协议于2011年被IETF定为标准 RFC 6455,并被 RFC7936 所补充规范。

—— 百度百科

WebSocket 是一个持久化的协议,这是相对于 http 非持久化来说的。

举个简单的例子,http1.0 的生命周期是以 request 作为界定的,也就是一个 request,一个 response,对于 http 来说,本次 client 与 server 的会话到此结束;而在 http1.1 中,稍微有所改进,即添加了 keep-alive,也就是在一个 http 连接中可以进行多个 request 请求和多个 response 接受操作。然而在实时通信中,并没有多大的作用,http 只能由 client 发起请求,server 才能返回信息,即 server 不能主动向 client 推送信息,无法满足实时通信的要求。而 WebSocket 可以进行持久化连接,即 client 只需进行一次握手,成功后即可持续进行数据通信,值得关注的是 WebSocket 实现 client 与 server 之间全双工通信,即 server 端有数据更新时可以主动推送给 client 端。

上图是一个演示client和server之间建立WebSocket连接时握手部分

client 建立 WebSocket 时向服务器端请求的信息

GET /chat HTTP/1.1 
  Host: server.example.com 
  Upgrade: websocket //告诉服务器现在发送的是WebSocket协议
  Connection: Upgrade 
  Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== //是一个Base64 encode的值,这个是浏览器随机生成的,用于验证服务器端返回数据是否是WebSocket助理
  Sec-WebSocket-Protocol: chat, superchat 
  Sec-WebSocket-Version: 13 
  Origin: http://example.com

服务器获取到 client 请求的信息后,根据 WebSocket 协议对数据进行处理并返回,其中要对 Sec-WebSocket-Key 进行加密等操作

HTTP/1.1 101 Switching Protocols 
  Upgrade: websocket //依然是固定的,告诉客户端即将升级的是Websocket协议,而不是mozillasocket,lurnarsocket或者shitsocket
  Connection: Upgrade 
  Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= //这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key,也就是client要求建立WebSocket验证的凭证
  Sec-WebSocket-Protocol: chat

PHP 服务端

?php

if(($socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP))  0) {
    
    echo "socket_create() 失败的原因是:".socket_strerror($sock)."\n";

}

if(($ret = socket_bind($socket,'127.0.0.1','9090'))  0) {
    
    echo "socket_bind() 失败的原因是:".socket_strerror($ret)."\n";

}

if(($ret = socket_listen($socket,3))  0) {
    
    echo "socket_listen() 失败的原因是:".socket_strerror($ret)."\n";

}
    

$all_sockets = [$socket];
    // socket 集合

do {
    
    $copy_sockets = $all_sockets;
       // 单独拷贝一份

    // 因为客户端是长连接,如果客户端非正常断开,服务端会在 socket_accept 阻塞,现在使用 select 非阻塞模式 socket
    if(socket_select($copy_sockets, $write, $except, 0) === false)
        exit('sosket_select error!');


    // 接收第一次 socket 连入,连入后移除服务端 socket
    if(in_array($socket, $copy_sockets)) {
    
        $client = socket_accept($socket);

        if($client) {
    
            $buf = socket_read($client, 1024);
    
            echo $buf;


            // 匹配 Sec-Websocket-Key 标识
            if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/i",$buf,$match)) {
    
                // 需要将 Sec-WebSocket-Key 值累加字符串,并依次进行 SHA-1 加密和 base64 加密
                $key = base64_encode(sha1($match[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',true));
    
                // 拼凑响应内容
                $res= "HTTP/1.1 101 Switching Protocol".PHP_EOL
                    ."Upgrade: WebSocket".PHP_EOL
                    ."Connection: Upgrade".PHP_EOL
                    ."WebSocket-Location: ws://127.0.0.1:9090".PHP_EOL
                    ."Sec-WebSocket-Accept: " . $key .PHP_EOL.PHP_EOL;
      // 注意这里,需要两个换行
                // 向客户端应答 Sec-WebSocket-Accept
                socket_write($client, $res, strlen($res));
    
                // 向客户端发送消息
                socket_write($client, buildMsg('socket ok'), 1024);
    

                // 加入客户端 socket
                $all_sockets[] = $client;

            }
    
            // 移除服务端 socket
            $key = array_search($socket, $copy_sockets);
    
            unset($copy_sockets[$key]);
    

            // socket_close($client);

        }

    }


    // 循环所有客户端 sockets
    foreach ($copy_sockets as $s) {
    
        // 获取客户端发给服务端的内容
        $buf = socket_read($s, 8024);
    
        echo strlen($buf).'---'.PHP_EOL;

        // 代表客户端主动关闭
        if(strlen($buf)  9) {
    
            $key = array_search($s, $all_sockets);
    
            unset($all_sockets[$key]);
    
            socket_close($s);
    
            continue;

        }
    
        // 输出
        echo getMsg($buf).PHP_EOL;

    }


}
    while(true);
    
socket_close($socket);


// 编码服务端向客户端发送的内容
function buildMsg($msg) {
    
    $frame = [];
    
    $frame[0] = '81';
    
    $len = strlen($msg);

    if ($len  126) {
    
        $frame[1] = $len  16 ? '0' . dechex($len) : dechex($len);

    }
 else if ($len  65025) {
    
        $s = dechex($len);
    
        $frame[1] = '7e' . str_repeat('0', 4 - strlen($s)) . $s;

    }
 else {
    
        $s = dechex($len);
    
        $frame[1] = '7f' . str_repeat('0', 16 - strlen($s)) . $s;

    }
    
    $data = '';
    
    $l = strlen($msg);
    
    for ($i = 0;
     $i  $l;
 $i++) {

        $data .= dechex(ord($msg{
$i}
    ));

    }
    
    $frame[2] = $data;
    
    $data = implode('', $frame);
    
    return pack("H*", $data);

}


// 解析客户端向服务端发送的内容
function getMsg($buffer) {
    
    $res = '';
    
    $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);

    }
    
    for ($index = 0;
     $index  strlen($data);
 $index++) {
    
        $res .= $data[$index] ^ $masks[$index % 4];

    }
    
    return $res;

}
    

客户端

!DOCTYPE html>
    
html lang="en">
    
head>
    
    meta charset="UTF-8">
    
    title>
    Title/title>
    
    script>
    
        // 创建一个Socket实例
        var socket = new WebSocket('ws://localhost:9090');


        // 打开Socket
        socket.onopen = function(event) {
    
            // 发送一个初始化消息
            socket.send("init msg");


        }
    ;

        socket.onmessage = function(event) {
    
            console.log('收到消息',event);


        }
    ;


        // 监听Socket的关闭
        socket.onclose = function(event) {
    
            console.log('关闭监听',event);

        }
    ;


        function  send()
        {
    
            socket.send("client msg");

        }
    
    /script>
    
/head>
    
body>
    
button onclick="send()">
    发送消息/button>
    
/body>
    
/html>
    

运行测试:

Client

Server



现在大家对于PHP实现WebSocket怎样做,有哪些要点的内容应该都清楚了吧,希望大家阅读完这篇文章能有所收获。最后,想要了解更多PHP实现WebSocket怎样做,有哪些要点的知识,欢迎关注网络,网络将为大家推送更多相关知识的文章。

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!


若转载请注明出处: PHP实现WebSocket怎样做,有哪些要点
本文地址: https://pptw.com/jishu/652655.html
CSS中绝对单位反应什么,怎样分类 PHP获取之前天数的时间戳方法是什么

游客 回复需填写必要信息