經朋友推薦去一家手遊公司面試,原諒我不厚道的只是好奇手遊公司到底是啥樣的才去的。工作雖然沒找到,但是跟他們的技術總監套近乎聊了幾乎一晚上,受益良多,知道了運營多個手遊大體需要的技術,當然還是厚道的不爆料了。面試中被問及socket和多執行緒程式設計,對這兩個知識點完全是空白,回來果斷開始研究。還是那句話,不懂裁縫的廚師不是好司機。何況這兩個知識也在前端開發的範疇之內。客戶端非常簡單,利用現代瀏覽器的websocket api,這裡介紹的很詳細:對我來說最快的學習途徑是實踐,所以找兩個東西來練手。乙個是websocket乙個是webwoker,今天先說第乙個。
要理解socket就要先理解http和tcp的區別,簡單說就是乙個是短鏈,乙個是長鏈,乙個是去伺服器拉資料,乙個是伺服器可以主動推資料。
而socket就是應用層與tcp/ip協議族通訊的中間軟體抽象層,它是一組介面。在設計模式中,socket其實就是乙個門面模式,它把複雜的tcp/ip協議族隱藏在socket介面後面,對使用者來說,一組簡單的介面就是全部,讓socket去組織資料,以符合指定的協議。-來自網路。
那麼如何用php+js做到伺服器推呢?
核心**:
var wsserver = 'ws:';var ws = new
websocket(wsserver);
ws.onmessage = function
(evt) ;
前兩行會向指定伺服器傳送乙個握手請求,如果伺服器返回合法的http頭,則握手成功,之後可通過監聽onmessage事件來處理伺服器發來的訊息。還有很多其他事件可監聽,見前面的url。
難點是伺服器,沒有了apache和nginx這些http伺服器在前面頂著,只用php該怎麼寫?
這裡有個教程講的很深入
寫之前捋一捋思路:
1 監聽:首先要掛起乙個程序來監聽來自客戶端的請求
2 握手:對於第一次合法的請求,傳送合法的header回去
3 保持連線:有新訊息到了就廣播出去。直到客戶端斷開
4 接受另乙個請求,重複2和3
關鍵**如下:
publicfunction
start_server()
//如果請求來自監聽埠那個套接字,則建立乙個新的套接字用於通訊
$this->add_accept($accept
);
continue
; }
$index = array_search($v, $this->accept);
if ($index === null
)
if (!@socket_recv($v, $data, 1024, 0) || !$data)
if (!$this->ishand[$index
])
continue
; }
$data = $this->decode($data
);
if(!empty($this->function['send']))
}sleep(1);
}}//
增加乙個初次連線的使用者
private
function add_accept($accept
) //
關閉乙個連線
private
function close($accept) }
//響應公升級協議
private
function upgrade($accept, $data, $index
) }
關鍵地方有那麼幾個,一是while(true)掛起程序,不然執行一次後程序就退出了。二是socket_select和socket_accept函式的使用。三是客戶端第一次請求時握手。
這個函式是同時接受多個連線的關鍵,我的理解它是為了阻塞程式繼續往下執行和自動選擇當前有活動的連線。
socket_select ($sockets, $write = null, $except = null, null);
$sockets可以理解為乙個陣列,這個陣列中存放的是檔案描述符。當它有變化(就是有新訊息到或者有客戶端連線/斷開)時,socket_select函式才會返回,繼續往下執行。
$write是監聽是否有客戶端寫資料,傳入null是不關心是否有寫變化。
$except是$sockets裡面要被排除的元素,傳入null是」監聽」全部。
最後乙個引數是超時時間
如果為0:則立即結束
如果為n>1: 則最多在n秒後結束,如遇某乙個連線有新動態,則提前返回
如果為null:如遇某乙個連線有新動態,則返回
為了理解,dump測試一下:
$this->cycle = $this->accept;$this->cycle = $this->socket;
var_dump($this->cycle);//
array(n),n>=1
socket_select($this->cycle, $write, $except, null);//
有活動後繼續往下
var_dump($this->cycle);//
array(0),n==0
這一測就完全明白了,socket_select之前把所有的socket連線都丟進去給它,其中乙個有活動時它就把那個連線丟擲來給我們用。表達能力有限,大概就是這麼個意思。。。
此函式接受唯一引數,即前面socket_create建立的socket檔案(控制代碼)。返回乙個新的資源,或者false。本函式將會通知socket_listen(),將會傳入乙個連線的socket資源。一旦成功建立socket連線,將會返回乙個新的socket資源,用於通訊。如果有多個socket在佇列中,那麼將會先處理第乙個。關鍵就是這裡:如果沒有socket連線,那麼本函式將會等待,直到有新socket進來。
如果前面不用socket_select在沒有socket的時候阻塞住程式,那麼就卡在這裡永遠無法結束了。
後面的流程就很清晰了,當有乙個新的客戶端請求到達,用socket_accept建立乙個資源,並加入到$this->accept連線池裡面。並將它的標示ishand設為false,那麼下次迴圈(因為$this->cycle = $this->socket;$this->cycle有變化,所以socket_select會返回)的時候就會執行upgrade握手。然後等待它的新訊息即可。
程式經除錯可以成功執行,php5.3+websocket13。
PHP SOCKET程式設計!
server.php php 確保在連線客戶端時不會超時 set time limit 0 設定ip和埠號 address 伺服器自己的ip port 埠號 建立乙個socket if sock socket create af inet sock stream sol tcp 0 繫結到socke...
php socket程式設計通訊
我們程式設計就是按這個順序的,請看下面的圖 建立乙個連線 socket socket create af inet,sock stream,sol tcp or die cannot create socket n 繫結socket到埠 result socket bind socket,host,...
PHP Socket 程式設計詳解
最近在做的專案有一項需要耗時任務在後台執行的功能,雖然php並不是非常適合做常駐後台的守護程序,但是由於專案主要 都是基於php實現,如 果執行在後台的守護程序改換別的語言會非常不方便。所以不可避免會涉及到web端和daemon部分的通訊,socket是乙個不錯的方式。socket的英文原義是 孔 ...