① 如何搭建 websocket伺服器
其實,在伺服器的選擇上很廣,基本上,主流語言都有WebSocket的伺服器端實現,而我們作為前端開發工程師,當然要選擇現在比較火熱的NodeJS作為我們的伺服器端環境了。
NodeJS本身並沒有原生的WebSocket支持,但是有第三方的實現(大家要是有興趣的話,完全可以參考WebSocket協議來做自己的實現),我們選擇了「ws」作為我們的伺服器端實現。
由於本文的重點是講解WebSocket,所以,對於NodeJS不做過多的介紹,不太熟悉的朋友可以去參考NodeJS入門指南(http://www.nodebeginner.org/index-zh-cn.html)。
安裝好NodeJS之後,我們需要安裝「ws」,也就是我們的WebSocket實現,安裝方法很簡單,在終端或者命令行中輸入:
npm install ws
,等待安裝完成就可以了。
接下來,我們需要啟動我們的WebSocket服務。首先,我們需要構建自己的HTTP伺服器,在NodeJS中構建一個簡單的HTTP伺服器很簡單,so easy。代碼如下:
var app = http.createServer(onRequest ).listen( 8888 );
onRequest()作為回調函數,它的作用是處理請求,然後做出響應,實際上就是根據接收的URL,在伺服器上查找相應的資源,最終返回給瀏覽器。
在構建了HTTP伺服器後,我們需要啟動WebSocket服務,代碼如下:
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer( { server : app } );
從代碼中可以看出,在初始化WebSocket服務時,把我們剛才構建好的HTTP實例傳遞進去就好。到這里,我們的服務端代碼差不多也就編寫完成了。怎麼樣?很簡單吧。
② 如何用php實現websocket
websocket需要php監聽一個固定的埠,而不是請求的時候再去執行 一般的主機服務無法實現此功能 如果你有伺服器的設置許可權,可以在伺服器上用php命令開啟埠,再用nginx做一個Websocket代理 大多數虛擬主機服務商是不支持自己配置伺服器的
③ php實現websocket實時消息推送
一、socket協議的簡介
WebSocket是什麼,有什麼優點
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之間的socket連接原理
1、下面是一個演示client和server之間建立WebSocket連接時握手部分
2、client與server建立socket時握手的會話內容,即request與response
a、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
b、伺服器獲取到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
3、socket建立連接原理圖:
三、PHP中建立websocket的過程講解
SocketService.php:
web.html:
④ php如何實現websocket
php有可用的websocket庫,不需要php-fpm。
目前比較成熟的有swoole(swoole.com),和workman(workman.net)
swoole是c寫的php擴展, 效率比nodejs還要高,workman是純php實現,兩者都號稱可以實現並發百萬TCP連接。
給你個例子:
這個要通過cmd運行的具體帶的參數有點忘記了
<?php
error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
//創建一個socket連接設置參數綁定監聽並且返回
$master=WebSocket("localhost",12345);
//標示是否已經進行過握手了
$is_shaked=false;
//是否已經關閉
$is_closed=true;
//將socket變為一個可用的socket
while(true){
//如果是關閉狀態並且是沒有握手的話則創建一個可用的socket(貌似第二個條件可以去除)
if($is_closed&&!$is_shaked){
if(($sock=socket_accept($master))<0){
echo"socket_accept()failed:reason:".socket_strerror($sock)." ";
}
//將關閉狀態修改為false
$is_closed=false;
}
//開始進行數據處理
process($sock);
}
//處理請求的函數
functionprocess($socket){
//先從獲取到全局變數
global$is_closed,$is_shaked;
//從socket中獲取數據
$buffer=socket_read($socket,2048);
//如果buffer返回值為false並且已經握手的話則斷開連接
if(!$buffer&&$is_shaked){
disconnect($socket);
}else{
//如果沒有握手的話則握手並且修改握手狀態
if($is_shaked==false){
$return_str=dohandshake($buffer);
$is_shaked=true;
}else{
//如果已經握手的話則送入deal函數中進行相應處理
$data_str=decode($buffer);//解析出來的從前端送來的內容
console($data_str);
$return_str=encode(deal($socket,$data_str));
//$return_str=encode($data_str);
}
//將應該返回的字元串寫入socket返回
socket_write($socket,$return_str,strlen($return_str));
}
}
functiondeal($socket,$msgObj){
$obj=json_decode($msgObj);
foreach($objas$key=>$value){
if($key=='close'){
disconnect($socket);
console('closesuccess');
return'closesuccess';
}elseif($key=='msg'){
console($value." ");
return$value;
}
}
}
//獲取頭部信息
functiongetheaders($req){
$r=$h=$o=null;
if(preg_match("/GET(.*)HTTP/",$req,$match)){$r=$match[1];}
if(preg_match("/Host:(.*) /",$req,$match)){$h=$match[1];}
if(preg_match("/Origin:(.*) /",$req,$match)){$o=$match[1];}
if(preg_match("/Sec-WebSocket-Key:(.*) /",$req,$match)){$key=$match[1];}
if(preg_match("/ (.*?)$/",$req,$match)){$data=$match[1];}
returnarray($r,$h,$o,$key,$data);
}
functionWebSocket($address,$port){
$master=socket_create(AF_INET,SOCK_STREAM,SOL_TCP)ordie("socket_create()failed");
socket_set_option($master,SOL_SOCKET,SO_REUSEADDR,1)ordie("socket_option()failed");
socket_bind($master,$address,$port)ordie("socket_bind()failed");
socket_listen($master,20)ordie("socket_listen()failed");
echo"ServerStarted:".date('Y-m-dH:i:s')." ";
echo"Mastersocket:".$master." ";
echo"Listeningon:".$address."port".$port." ";
return$master;
}
functiondohandshake($buffer){
list($resource,$host,$origin,$key,$data)=getheaders($buffer);
echo"resourceis$resource ";
echo"originis$origin ";
echo"hostis$host ";
echo"keyis$key ";
$response_key=base64_encode(sha1($key.'258EAFA5-E914-47DA-95CA-C5AB0DC85B11',true));
$return_str="HTTP/1.1101SwitchingProtocols ".
"Upgrade:websocket ".
"Connection:Upgrade ".
"Sec-WebSocket-Accept:$response_key ";
return$return_str;
}
functionconsole($msg){
$msg=transToGBK($msg);
echo"$msg ";
return$msg;
}
functiondecode($msg=""){
$mask=array();
$data="";
$msg=unpack("H*",$msg);
$head=substr($msg[1],0,2);
if(hexdec($head{1})===8){
$data=false;
}elseif(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));
$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++;
}
}
return$data;
}
functionencode($msg=""){
$frame=array();
$frame[0]="81";
$msg.='isok';
$len=strlen($msg);
$frame[1]=$len<16?"0".dechex($len):dechex($len);
$frame[2]=ord_hex($msg);
$data=implode("",$frame);
returnpack("H*",$data);
}
functiontransToGBK($s){//UTF8->GBK
//echo$s;
returniconv("UTF-8","GBK",$s);
return$s;
}
functionord_hex($data){
$msg="";
$l=strlen($data);
for($i=0;$i<$l;$i++){
//ord是返回字元串第一個字元的ascii值
//dechex把十進制轉換為十六進制
$msg.=dechex(ord($data{$i}));
}
return$msg;
}
functiondisconnect($socket){
global$is_shaked,$is_closed;
$is_shaked=false;
$is_closed=true;
socket_close($socket);
}
?>