最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

PHP實現(xiàn)WebSocket實例詳解

 更新時間:2021年09月07日 08:57:02   作者:Azure沫  
這篇文章主要介紹了PHP實現(xiàn)WebSocket實例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下

WebSocket 是什么?

摘抄網上的一些解釋:

WebSocket 協(xié)議是基于 TCP 的一種新的網絡協(xié)議。它實現(xiàn)了瀏覽器與服務器全雙工(full-duplex)通信——允許服務器主動發(fā)送信息給客戶端。

WebSocket 通信協(xié)議于2011年被 IETF 定為標準 RFC 6455,并被 RFC7936 所補充規(guī)范。

—— 百度百科

WebSocket 是一個持久化的協(xié)議,這是相對于 http 非持久化來說的。

舉個簡單的例子,http1.0 的生命周期是以 request 作為界定的,也就是一個 request,一個 response,對于 http 來說,本次 client 與 server 的會話到此結束;而在 http1.1 中,稍微有所改進,即添加了 keep-alive,也就是在一個 http 連接中可以進行多個 request 請求和多個 response 接受操作。然而在實時通信中,并沒有多大的作用,http 只能由 client 發(fā)起請求,server 才能返回信息,即 server 不能主動向 client 推送信息,無法滿足實時通信的要求。而 WebSocket 可以進行持久化連接,即 client 只需進行一次握手,成功后即可持續(xù)進行數(shù)據通信,值得關注的是 WebSocket 實現(xiàn) client 與 server 之間全雙工通信,即 server 端有數(shù)據更新時可以主動推送給 client 端。

上圖是一個演示client和server之間建立WebSocket連接時握手部分

client 建立 WebSocket 時向服務器端請求的信息

GET /chat HTTP/1.1 
  Host: server.example.com 
  Upgrade: websocket //告訴服務器現(xiàn)在發(fā)送的是WebSocket協(xié)議
  Connection: Upgrade 
  Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== //是一個Base64 encode的值,這個是瀏覽器隨機生成的,用于驗證服務器端返回數(shù)據是否是WebSocket助理
  Sec-WebSocket-Protocol: chat, superchat 
  Sec-WebSocket-Version: 13 
  Origin: http://example.com

服務器獲取到 client 請求的信息后,根據 WebSocket 協(xié)議對數(shù)據進行處理并返回,其中要對 Sec-WebSocket-Key 進行加密等操作

HTTP/1.1 101 Switching Protocols 
  Upgrade: websocket //依然是固定的,告訴客戶端即將升級的是Websocket協(xié)議,而不是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 阻塞,現(xiàn)在使用 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));
                // 向客戶端發(fā)送消息
                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);
        }
    }

    // 循環(huán)所有客戶端 sockets
    foreach ($copy_sockets as $s) {
        // 獲取客戶端發(fā)給服務端的內容
        $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);

// 編碼服務端向客戶端發(fā)送的內容
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);
}

// 解析客戶端向服務端發(fā)送的內容
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>
        // 創(chuàng)建一個Socket實例
        var socket = new WebSocket('ws://localhost:9090');

        // 打開Socket
        socket.onopen = function(event) {
            // 發(fā)送一個初始化消息
            socket.send("init msg");

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

        };

        // 監(jiān)聽Socket的關閉
        socket.onclose = function(event) {
            console.log('關閉監(jiān)聽',event);
        };

        function  send()
        {
            socket.send("client msg");
        }
    </script>
</head>
<body>
<button onclick="send()">發(fā)送消息</button>
</body>
</html>

運行測試:

Client

Server

到此這篇關于PHP實現(xiàn)WebSocket實例詳解的文章就介紹到這了,更多相關PHP實現(xiàn)WebSocket內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • PHP Streams(流)詳細介紹及使用

    PHP Streams(流)詳細介紹及使用

    這篇文章主要介紹了PHP Streams(流)詳細介紹及使用,PHP Streams是內置核心操作,可能一般的開發(fā)者很少用,它用于統(tǒng)一文件、網絡、數(shù)據壓縮等類文件操作方式,并為這些類文件操作提供一組通用的函數(shù)接口,需要的朋友可以參考下
    2015-05-05
  • Laravel中前端js上傳圖片到七牛云的示例代碼

    Laravel中前端js上傳圖片到七牛云的示例代碼

    本篇文章主要介紹了Laravel中前端js上傳圖片到七牛云的示例代碼,具有一定的參考價值,有興趣的可以了解一下
    2017-09-09
  • Yii使用Captcha驗證碼的方法

    Yii使用Captcha驗證碼的方法

    這篇文章主要介紹了Yii使用Captcha驗證碼的方法,結合實例形式分析了Yii使用Captcha驗證碼的MVC三層具體實現(xiàn)技巧,需要的朋友可以參考下
    2015-12-12
  • Laravel 自帶的Auth驗證登錄方法

    Laravel 自帶的Auth驗證登錄方法

    今天小編就為大家分享一篇Laravel 自帶的Auth驗證登錄方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09
  • php生成靜態(tài)頁面的簡單示例

    php生成靜態(tài)頁面的簡單示例

    這篇文章主要介紹了php生成靜態(tài)頁面的簡單示例,需要的朋友可以參考下
    2014-04-04
  • PHP jQuery+Ajax結合寫批量刪除功能

    PHP jQuery+Ajax結合寫批量刪除功能

    這篇文章主要介紹了PHP jQuery+Ajax結合寫批量刪除功能的相關資料,需要的朋友可以參考下
    2017-05-05
  • Symfony實現(xiàn)行為和模板中取得request參數(shù)的方法

    Symfony實現(xiàn)行為和模板中取得request參數(shù)的方法

    這篇文章主要介紹了Symfony實現(xiàn)行為和模板中取得request參數(shù)的方法,實例分析了Symfony針對行為和方法中參數(shù)獲取的技巧,需要的朋友可以參考下
    2016-03-03
  • php下載文件,添加響應頭的簡單實例

    php下載文件,添加響應頭的簡單實例

    下面小編就為大家?guī)硪黄猵hp下載文件,添加響應頭的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-09-09
  • php基于CodeIgniter實現(xiàn)圖片上傳、剪切功能

    php基于CodeIgniter實現(xiàn)圖片上傳、剪切功能

    這篇文章主要為大家詳細介紹了php基于CodeIgniter實現(xiàn)圖片上傳、剪切功能,具有參考價值,感興趣的朋友可以參考一下
    2016-05-05
  • 用PHP做了一個領取優(yōu)惠券活動的示例代碼

    用PHP做了一個領取優(yōu)惠券活動的示例代碼

    這篇文章主要介紹了用PHP做了一個領取優(yōu)惠券活動的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-07-07

最新評論

广东省| 道孚县| 郴州市| 汕尾市| 鹿泉市| 始兴县| 大姚县| 巢湖市| 秦皇岛市| 宁乡县| 桃江县| 林周县| 织金县| 泾阳县| 右玉县| 莱西市| 宿州市| 宁波市| 洪江市| 长岭县| 菏泽市| 衢州市| 金乡县| 胶州市| 石家庄市| 涞水县| 天峻县| 新化县| 图们市| 临潭县| 大关县| 宜良县| 土默特右旗| 综艺| 岗巴县| 宾阳县| 东城区| 讷河市| 凤凰县| 黄龙县| 濉溪县|