php基于websocket搭建簡(jiǎn)易聊天室實(shí)踐
本文實(shí)例講述了php基于websocket搭建簡(jiǎn)易聊天室實(shí)踐。分享給大家供大家參考。具體如下:
1、前言
公司游戲里面有個(gè)簡(jiǎn)單的聊天室,了解了之后才知道是node+websocket做的,想想php也來做個(gè)簡(jiǎn)單的聊天室。于是搜集各種資料看文檔、找實(shí)例自己也寫了個(gè)簡(jiǎn)單的聊天室。
http連接分為短連接和長(zhǎng)連接。短連接一般可以用ajax實(shí)現(xiàn),長(zhǎng)連接就是websocket。短連接實(shí)現(xiàn)起來比較簡(jiǎn)單,但是太過于消耗資源。websocket高效不過兼容存在點(diǎn)問題。websocket是html5的資源
2、前端
前端實(shí)現(xiàn)websocket很簡(jiǎn)單直接
//連接websocket
var ws = new WebSocket("ws://127.0.0.1:8000");
//成功連接websoc的時(shí)候
ws.onopen = function(){}
//成功獲取服務(wù)端輸出的消息
ws.onmessage = function(e){}
//連接錯(cuò)誤的時(shí)候
ws.onerror = function(){}
//向服務(wù)端發(fā)送數(shù)據(jù)
ws.send();
3、后臺(tái)
websocket的難點(diǎn)主要在后臺(tái)
3.1websocket連接過程
websocket 通信圖解 這是一個(gè)簡(jiǎn)易的客戶端和服務(wù)端的通信圖解,php主要就做的就是接受加密key 并返回 其中完成套接字的創(chuàng)建和握手操作

下圖是一張?jiān)敿?xì)的服務(wù)端處理websocket的流程圖

3.2 代碼實(shí)踐
服務(wù)端做的流程大致是:
- 掛起一個(gè)socket套接字進(jìn)程等待連接
- 有socket連接之后遍歷套接字?jǐn)?shù)組
- 沒有握手的進(jìn)行握手操作,如果已經(jīng)握手則接收數(shù)據(jù)解析并寫入緩沖區(qū)進(jìn)行輸出
下面是示例代碼(我寫的是一個(gè)類所以代碼是根據(jù)函數(shù)分段的),文底給出github地址以及自己遇到的一些坑
1、首先是創(chuàng)建套接字
//建立套接字
public function createSocket($address,$port)
{
//創(chuàng)建一個(gè)套接字
$socket= socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//設(shè)置套接字選項(xiàng)
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
//綁定IP地址和端口
socket_bind($socket,$address,$port);
//監(jiān)聽套接字
socket_listen($socket);
return $socket;
}
2、將套接字放入數(shù)組
public function __construct($address,$port)
{
//建立套接字
$this->soc=$this->createSocket($address,$port);
$this->socs=array($this->soc);
}
3、掛起進(jìn)程遍歷套接字?jǐn)?shù)組,主要操作都是在這里面完成的
public function run(){
//掛起進(jìn)程
while(true){
$arr=$this->socs;
$write=$except=NULL;
//接收套接字?jǐn)?shù)字 監(jiān)聽他們的狀態(tài)
socket_select($arr,$write,$except, NULL);
//遍歷套接字?jǐn)?shù)組
foreach($arr as $k=>$v){
//如果是新建立的套接字返回一個(gè)有效的 套接字資源
if($this->soc == $v){
$client=socket_accept($this->soc);
if($client <0){
echo "socket_accept() failed";
}else{
// array_push($this->socs,$client);
// unset($this[]);
//將有效的套接字資源放到套接字?jǐn)?shù)組
$this->socs[]=$client;
}
}else{
//從已連接的socket接收數(shù)據(jù) 返回的是從socket中接收的字節(jié)數(shù)
$byte=socket_recv($v, $buff,20480, 0);
//如果接收的字節(jié)是0
if($byte<7)
continue;
//判斷有沒有握手沒有握手則進(jìn)行握手,如果握手了 則進(jìn)行處理
if(!$this->hand[(int)$client]){
//進(jìn)行握手操作
$this->hands($client,$buff,$v);
}else{
//處理數(shù)據(jù)操作
$mess=$this->decodeData($buff);
//發(fā)送數(shù)據(jù)
$this->send($mess,$v);
}
}
}
}
}
4、進(jìn)行握手 流程是接收websocket內(nèi)容從Sec-WebSocket-Key:中獲取key并通過加密算法寫入緩沖區(qū)客戶端會(huì)進(jìn)行驗(yàn)證(自動(dòng)驗(yàn)證不需要我們處理)
public function hands($client,$buff,$v)
{
//提取websocket傳的key并進(jìn)行加密 (這是固定的握手機(jī)制獲取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";
//將套接字寫入緩沖區(qū)
socket_write($v,$new_message,strlen($new_message));
// socket_write(socket,$upgrade.chr(0), strlen($upgrade.chr(0)));
//標(biāo)記此套接字握手成功
$this->hand[(int)$client]=true;
}
5、解析客戶端的數(shù)據(jù)(我這里沒有進(jìn)行加密,如果有需要也可以自己加密 )
//解析數(shù)據(jù)
public function decodeData($buff)
{
//$buff 解析數(shù)據(jù)幀
$mask = array();
$data = '';
$msg = unpack('H*',$buff); //用unpack函數(shù)從二進(jìn)制將數(shù)據(jù)解碼
$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));
//遇到的問題 剛連接的時(shí)候就發(fā)送數(shù)據(jù) 顯示 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++;
}
//發(fā)送數(shù)據(jù)到客戶端
//如果長(zhǎng)度大于125 將數(shù)據(jù)分塊
$block=str_split($data,125);
$mess=array(
'mess'=>$block[0],
);
return $mess;
}
6、將套接字寫入緩沖區(qū)
//發(fā)送數(shù)據(jù)
public function send($mess,$v)
{
//遍歷套接字?jǐn)?shù)組 成功握手的 進(jìn)行數(shù)據(jù)群發(fā)
foreach ($this->socs as $keys => $values) {
//用系統(tǒng)分配的套接字資源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、運(yùn)行方法
github地址git@github.com:rsaLive/websocket.git
①最好在控制臺(tái)運(yùn)行server.php
轉(zhuǎn)到server.php腳本目錄(可以先php -v 看下有沒有配置php如果沒有Linux配置下bash windows 配置下path)
php -f server.php

如果有錯(cuò)誤會(huì)提示

②通過服務(wù)器訪問html文件


8、踩過的坑,打開調(diào)試工作方便查看錯(cuò)誤
①server.php 掛起的進(jìn)程中可以打印輸出的,如果出現(xiàn)問題可以在代碼中加入打印來調(diào)試
可以在各個(gè)判斷里面做標(biāo)記在控制臺(tái)查看代碼運(yùn)行在哪個(gè)區(qū)間
不過每次修改完代碼之后需要重新運(yùn)行腳本 php server.php
②如果出現(xiàn)這種錯(cuò)誤可能是

1、在與服務(wù)器初始套接字的時(shí)候發(fā)送數(shù)據(jù) (在第一次與服務(wù)器驗(yàn)證握手的時(shí)候不能發(fā)送內(nèi)容)
2、如果已經(jīng)驗(yàn)證過了但是客戶端沒有發(fā)送或者發(fā)送的消息為空也會(huì)出現(xiàn)這樣的情況
所以要檢驗(yàn)已連接的套接字的數(shù)據(jù)

③可能瀏覽器不支持或者服務(wù)端沒有開啟socket開始之前最好驗(yàn)證下
if (window.WebSocket){
console.log("This browser supports WebSocket!");
} else {
console.log("This browser does not support WebSocket.");
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- php+websocket 實(shí)現(xiàn)的聊天室功能詳解
- 基于Swoole實(shí)現(xiàn)PHP與websocket聊天室
- php+html5基于websocket實(shí)現(xiàn)聊天室的方法
- php socket實(shí)現(xiàn)的聊天室代碼分享
- PHP實(shí)現(xiàn)簡(jiǎn)單聊天室(附源碼)
- 用PHP+MySQL搭建聊天室功能實(shí)例代碼
- php寫的簡(jiǎn)易聊天室代碼
- 基于HTTP長(zhǎng)連接的"服務(wù)器推"技術(shù)的php 簡(jiǎn)易聊天室
- 如何用PHP websocket實(shí)現(xiàn)網(wǎng)頁實(shí)時(shí)聊天
相關(guān)文章
php實(shí)現(xiàn)中文轉(zhuǎn)數(shù)字
這里給大家分享的是一則使用php實(shí)現(xiàn)的中文轉(zhuǎn)數(shù)字的代碼,非常智能,也很完美,有需要的小伙伴可以參考下。2016-02-02
php 反斜杠處理函數(shù)addslashes()和stripslashes()實(shí)例詳解
PHP自帶的庫函數(shù) addslashes() 和 stripslashes() 都屬于字符串處理類函數(shù), 本文章向大家介紹php 反斜杠處理函數(shù)addslashes()和stripslashes(),需要的朋友可以參考下2016-12-12
布隆過濾器(bloom filter)及php和redis實(shí)現(xiàn)布隆過濾器的方法
這篇文章主要介紹了布隆過濾器(bloom filter)介紹以及php和redis實(shí)現(xiàn)布隆過濾器實(shí)現(xiàn)方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12

