本篇文章主要講解php+websocket搭建簡易聊天室實踐,文中有關php,websocket的內容,請有需要的人蔘考。
本文執行個體講述了php基於websocket搭建簡易聊天室實踐。分享給大家供大家參考。具體如下:
1、前言
公司遊戲裡面有個簡單的聊天室,瞭解了之後才知道是node+websocket做的,想想php也來做個簡單的聊天室。於是搜集各種資料看文檔、找執行個體自己也寫了個簡單的聊天室。
http串連分為短串連和長串連。短串連一般可以用ajax實現,長串連就是websocket。短串連實現起來比較簡單,但是太過於消耗資源。websocket高效不過相容存在點問題。websocket是html5的資源
2、前端
前端實現websocket很簡單直接
//串連websocketvar ws = new WebSocket("ws://127.0.0.1:8000");//成功串連websoc的時候ws.onopen = function(){}//成功擷取服務端輸出的訊息ws.onmessage = function(e){}//串連錯誤的時候ws.onerror = function(){}//向服務端發送資料ws.send();
3、後台
websocket的痛點主要在後台
3.1websocket串連過程
websocket 通訊圖解 這是一個簡易的用戶端和服務端的通訊圖解,php主要就做的就是接受加密key 並返回 其中完成通訊端的建立和握手操作
是一張詳細的服務端處理websocket的流程圖
3.2 代碼實踐
服務端做的流程大致是:
掛起一個socket通訊端進程等待串連
有socket串連之後遍曆通訊端數組
沒有握手的進行握手操作,如果已經握手則接收資料解析並寫入緩衝區進行輸出
下面是範例程式碼(我寫的是一個類所以代碼是根據函數分段的),文底給出github地址以及自己遇到的一些坑
1、首先是建立通訊端
//建立通訊端 public function createSocket($address,$port) { //建立一個通訊端 $socket= socket_create(AF_INET, SOCK_STREAM, SOL_TCP); //設定通訊端選項 socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); //綁定IP地址和連接埠 socket_bind($socket,$address,$port); //監聽通訊端 socket_listen($socket); return $socket; }
2、將通訊端放入數組
public function __construct($address,$port) { //建立通訊端 $this->soc=$this->createSocket($address,$port); $this->socs=array($this->soc); }
3、掛起進程遍曆通訊端數組,主要操作都是在這裡面完成的
public function run(){ //掛起進程 while(true){ $arr=$this->socs; $write=$except=NULL; //接收通訊端數字 監聽他們的狀態 socket_select($arr,$write,$except, NULL); //遍曆通訊端數組 foreach($arr as $k=>$v){ //如果是建立立的通訊端返回一個有效 通訊端資源 if($this->soc == $v){ $client=socket_accept($this->soc); if($client <0){ echo "socket_accept() failed"; }else{ // array_push($this->socs,$client); // unset($this[]); //將有效通訊端資源放到通訊端數組 $this->socs[]=$client; } }else{ //從已串連的socket接收資料 返回的是從socket中接收的位元組數 $byte=socket_recv($v, $buff,20480, 0); //如果接收的位元組是0 if($byte<7) continue; //判斷有沒有握手沒有握手則進行握手,如果握手了 則進行處理 if(!$this->hand[(int)$client]){ //進行握手操作 $this->hands($client,$buff,$v); }else{ //處理資料操作 $mess=$this->decodeData($buff); //發送資料 $this->send($mess,$v); } } } } }
4、進行握手 流程是接收websocket內容從Sec-WebSocket-Key:中擷取key並通過密碼編譯演算法寫入緩衝區用戶端會進行驗證(自動驗證不需要我們處理)
public function hands($client,$buff,$v) { //提取websocket傳的key並進行加密 (這是固定的握手機制擷取Sec-WebSocket-Key:裡面的key) $buf = substr($buff,strpos($buff,'Sec-WebSocket-Key:')+18); //去除換行空白字元 $key = trim(substr($buf,0,strpos($buf,"\r\n"))); //固定的密碼編譯演算法 $new_key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true)); $new_message = "HTTP/1.1 101 Switching Protocols\r\n"; $new_message .= "Upgrade: websocket\r\n"; $new_message .= "Sec-WebSocket-Version: 13\r\n"; $new_message .= "Connection: Upgrade\r\n"; $new_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n"; //將通訊端寫入緩衝區 socket_write($v,$new_message,strlen($new_message)); // socket_write(socket,$upgrade.chr(0), strlen($upgrade.chr(0))); //標記此通訊端握手成功 $this->hand[(int)$client]=true; }
5、解析用戶端的資料(我這裡沒有進行加密,如果有需要也可以自己加密 )
//解析資料 public function decodeData($buff) { //$buff 解析資料幀 $mask = array(); $data = ''; $msg = unpack('H*',$buff); //用unpack函數從二進位將資料解碼 $head = substr($msg[1],0,2); if (hexdec($head{1}) === 8) { $data = false; }else if (hexdec($head{1}) === 1){ $mask[] = hexdec(substr($msg[1],4,2)); $mask[] = hexdec(substr($msg[1],6,2)); $mask[] = hexdec(substr($msg[1],8,2)); $mask[] = hexdec(substr($msg[1],10,2)); //遇到的問題 剛串連的時候就發送資料 顯示 state connecting $s = 12; $e = strlen($msg[1])-2; $n = 0; for ($i=$s; $i<= $e; $i+= 2) { $data .= chr($mask[$n%4]^hexdec(substr($msg[1],$i,2))); $n++; } //發送資料到用戶端 //如果長度大於125 將資料分塊 $block=str_split($data,125); $mess=array( 'mess'=>$block[0], ); return $mess; }
6、將通訊端寫入緩衝區
//發送資料 public function send($mess,$v) { //遍曆通訊端數組 成功握手的 進行資料群發 foreach ($this->socs as $keys => $values) { //用系統分配的通訊端資源id作為使用者暱稱 $mess['name']="Tourist's socket:{$v}"; $str=json_encode($mess); $writes ="\x81".chr(strlen($str)).$str; // ob_flush(); // flush(); // sleep(3); if($this->hand[(int)$values]) socket_write($values,$writes,strlen($writes)); } }
7、運行方法
github地址git@github.com:rsaLive/websocket.git
①最好在控制台運行server.php
轉到server.php指令碼目錄(可以先php -v 看下有沒有配置php如果沒有Linux配置下bash windows 配置下path)
php -f server.php
如果有錯誤會提示
②通過伺服器訪問html檔案
8、踩過的坑,開啟調試工作方便查看錯誤
①server.php 掛起的進程中可以列印輸出的,如果出現問題可以在代碼中加入列印來調試
可以在各個判斷裡面做標記在控制台查看代碼運行在哪個區間
不過每次修改完代碼之後需要重新運行指令碼 php server.php
②如果出現這種錯誤可能是
1、在與伺服器初始通訊端的時候發送資料 (在第一次與伺服器驗證握手的時候不能發送內容)
2、如果已經驗證過了但是用戶端沒有發送或者發送的訊息為空白也會出現這樣的情況
所以要檢驗已串連的通訊端的資料
③可能瀏覽器不支援或者服務端沒有開啟socket開始之前最好驗證下
if (window.WebSocket){ console.log("This browser supports WebSocket!");} else { console.log("This browser does not support WebSocket.");}
以上就是本文的全部內容,希望對大家的學習有所協助。