**url:
下面我畫了乙個圖演示 client 和 server 之間建立 websocket 連線時握手部分,這個部分在 node 中可以十分輕鬆的完成,因為 node 提供的 net 模組已經對 socket 套接字做了封裝處理,開發者使用的時候只需要考慮資料的互動而不用處理連線的建立。而 php 沒有,從 socket 的連線、建立、繫結、監聽等,這些都需要我們自己去操作,所以有必要拿出來再說一說。
① 和 ② 實際上就是乙個 http 的請求和響應,只不過我們在處理的過程中我們拿到的是沒有經過解析的字串。如:
複製**
**如下:
我們往常看到的請求是這個樣子,當這東西到了伺服器端,我們可以通過一些**庫直接拿到這些資訊。
一、php 中處理 websocket
websocket 連線是由客戶端主動發起的,所以一切要從客戶端出發。第一步是要解析拿到客戶端發過來的 sec-websocket-key 字串。
複製**
**如下:
client 請求的格式
首先 php 建立乙個 socket 連線,監聽埠的資訊。
1. socket 連線的建立
關於 socket 套接字的建立,相信很多大學修過計算機網路的人都知道了,下面是一張連線建立的過程:
複製**
**如下:
// 建立乙個 socket 套接字
$master = socket_create(af_inet, sock_stream, sol_tcp);
socket_set_option($master, sol_socket, so_reuseaddr, 1);
socket_bind($master, $address, $port);
socket_listen($master);
相比 node,這個地方的處理實在是太麻煩了,上面幾行**並未建立連線,只不過這些**是建立乙個 socket 套接字必須要寫的東西。由於處理過程稍微有複雜,所以我把各種處理寫進了乙個類中,方便管理和呼叫。
複製**
**如下:
class ws else
} else else }}
}}}
上面這段**是經過我除錯了的,沒太大的問題,如果想測試的話,可以在 cmd 命令列中鍵入 php /path/to/demo.php;當然,上面只是乙個類,如果要測試的話,還得新建乙個例項。
複製**
**如下:
$ws = new ws('localhost', 4000);
客戶端**可以稍微簡單點:
複製**
**如下:
var ws = new websocket("ws://localhost:4000");
ws.onopen = function();
ws.onerror = function();
執行伺服器**,當客戶端連線的時候,我們可以看到:
2. 提取 sec-websocket-key 資訊
複製**
**如下:
function getkey($req)
return $key; }
這裡比較簡單,直接正則匹配,websocket 資訊頭一定包含 sec-websocket-key,所以我們匹配起來也比較快捷~
3. 加密 sec-websocket-key
複製**
**如下:
function encry($req)
將 sha-1 加密後的字串再進行一次 base64 加密。如果加密演算法錯誤,客戶端在進行校檢的時候會直接報錯:
4. 應答 sec-websocket-accept
複製**
**如下:
function dohandshake($socket, $req)
這裡千萬要注意,每乙個請求和相應的格式,最後有乙個空行,也就是 \r\n,開始測試的時候把這東西給弄丟了,糾結了半天。
當客戶端成功校檢key後,會觸發 onopen 函式:
5. 資料幀處理
複製**
**如下:
// 解析資料幀
function decode($buffer) else if ($len === 127) else
for ($index = 0; $index < strlen($data); $index++)
return $decoded;}
這裡涉及的編碼問題在前文中已經提到過了,這裡就不贅述,php 對字元處理的函式太多了,也記得不是特別清楚,這裡就沒有詳細的介紹解碼程式,直接把客戶端傳送的資料原樣返回,可以算是乙個聊天室的模式吧。
複製**
**如下:
// 返回幀資訊處理
function frame($s)
$ns = "";
foreach ($a as $o)
return $ns; }
// 返回資料
function send($client, $msg)
客戶端**:
複製**
**如下:
var ws = new websocket("ws://localhost:4000");
ws.onopen = function();
ws.onmessage = function(e);
ws.onerror = function();
ws.send("李靖");
在連通之後傳送資料,伺服器原樣返回:
二、注意問題
1. websocket 版本問題
客戶端在握手時的請求中有sec-websocket-version: 13,這樣的版本標識,這個是乙個公升級版本,現在的瀏覽器都是使用的這個版本。而以前的版本在資料加密的部分更加麻煩,它會傳送兩個key:
複製**
**如下:
如果是這種版本(比較老,已經沒在使用了),需要通過下面的方式獲取
複製**
**如下:
function encry($key1,$key2,$l8b)
//some math
$key1_sec = pack("n",$key1_num / $key1_spc);
$key2_sec = pack("n",$key2_num / $key2_spc);
return md5($key1_sec.$key2_sec.$l8b,1);}
只能無限吐槽這種驗證方式!相比 nodejs 的 websocket 操作方式:
複製**
**如下:
//伺服器程式
var crypto = require('crypto');
var ws = '258eafa5-e914-47da-95ca-c5ab0dc85b11';
require('net').createserver(function(o)else;
});}).listen(8000);
2. 資料幀解析**
本文沒有給出 decodeframe 這樣資料幀解析**,前文中給出了資料幀的格式,解析純屬體力活。
PHP實現websocket通訊的方法示例
執行方法 首先先修改server.php與index.html的ip 通過命令列執行 php路徑 php.exe 檔案路徑 server.php 然後通過瀏覽器開啟index.html server.php config array address 192.168.0.200 port 8000 e...
ConcurrentHashMap使用示例
concurrenthashmap是併發效率更高的map,用來替換其他執行緒安全的map容器,比如hashtable和collections.synchronizedmap。實際上,併發執行時,執行緒安全的容器只能保證自身的資料不被破壞,但無法保證業務的行為是否正確。錯誤的理解這裡的執行緒安全,不恰...
webSocket 基本使用
安裝 websocketnpm i ws建立物件const websocket require ws const wss newwebsocket.srever 監聽事件 連線事件 wss.on connection client 接收資料事件 wss.on connection client 傳送...