您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關PHP如何實現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 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”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。