啟用 Socket 服務(wù)器

2018-06-13 15:41 更新

ModPHP 提供了一個(gè)默認(rèn)的 Socket 服務(wù)器程序邏輯,用以配合模塊數(shù)據(jù)操作。

要啟動(dòng)默認(rèn)的 Socket 服務(wù)器,你只需要在服務(wù)器的控制臺(tái)中運(yùn)行站點(diǎn)根目錄的 socket-server.php 文件即可。如果你使用 Apache 服務(wù)器,你也可以在瀏覽器中開啟,但需要驗(yàn)證管理員權(quán)限。注意:瀏覽器可能無法加載 socket-server.php 頁(yè)面輸出的內(nèi)容,訪問后直接關(guān)閉窗口即可。

監(jiān)聽端口由 config('mod.SocketServer.port') 設(shè)置,默認(rèn)為 8080。

開啟 Socket 服務(wù)器不會(huì)影響正常的 Apache 網(wǎng)站,但是如果你的程序代碼經(jīng)過改動(dòng)(例如更新系統(tǒng)),則需要重新啟動(dòng) Socket 服務(wù)。如果你是在瀏覽器中啟用 Socket 服務(wù)器的,那么你需要通過關(guān)閉 Apache 來關(guān)閉 Socket 服務(wù)器,然后才能再次重啟它。

當(dāng) Socket 服務(wù)器啟動(dòng)之后,你就可以通過 JSON 進(jìn)行數(shù)據(jù)交換了,所有能夠通過 URL 訪問 mod.php 進(jìn)行請(qǐng)求的操作,也能通過 Socket 服務(wù)器進(jìn)行。

該 Socket 服務(wù)器僅用于傳輸文本數(shù)據(jù)(JSON),不支持傳輸二進(jìn)制數(shù)據(jù),但是,你可以將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為文本(例如圖像轉(zhuǎn) base64)進(jìn)行傳輸,或者自己編寫另外的 Socket 程序邏輯。

客戶端通過發(fā)送 JSON 數(shù)據(jù)向服務(wù)器提交請(qǐng)求,服務(wù)器將操作結(jié)果回應(yīng)以 JSON 數(shù)據(jù),實(shí)現(xiàn)前后端一致。需要注意的是,除非是重現(xiàn)會(huì)話,否則 JSON 中必須包含 {obj} 和 {act} 屬性,其他屬性將作為請(qǐng)求參數(shù)。

重現(xiàn)會(huì)話:


如果客戶端已經(jīng)通過其他方式進(jìn)行了用戶登錄,如 AJAX,那么可以將 cookie 中的 Session ID 傳給 Socket 服務(wù)器,從而在 WebSocket 中恢復(fù)登錄狀態(tài)。當(dāng)然,如果你沒有通過其他方式進(jìn)行登錄,也可以使用 WebSocket 進(jìn)行登錄,登錄后會(huì)將用戶信息和 Session ID 通過 JSON 同時(shí)返回給客戶端,客戶端將 Session ID 寫入 Cookie 中,從而在瀏覽其他頁(yè)面時(shí)也保持會(huì)話。

重現(xiàn)會(huì)話示例:

var ws = new WebSocket('ws://localhost:8080');
ws.open = function(){
    var sid = document.cookie.match(/PHPSESSID=(.*)\b/)[1];
    ws.send(JSON.stringify({PHPSESSID: sid}));
}

登錄示例:

var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function(){
    var data = {
        obj: 'user',
        act: 'login',
        user: 'someone',
        user_password: 'not_show_here'
    };
    ws.send(JSON.stringify(data));
}
ws.onmessage = function(e){
    var result = JSON.parse(e.data);
    if(result.success && result.PHPSESSID){
        document.cookie += 'PHPSESSID='+result.PHPSESSID; //將 Session ID 寫到 cookie 中
    }
}

需要注意的是,在重現(xiàn)會(huì)話或者使用 WebSocket 進(jìn)行登錄之后,之后的其他操作就已經(jīng)運(yùn)行在已登錄狀態(tài)了,服務(wù)器會(huì)保存登錄信息,不需要客戶端再提交 Session ID。例如,要獲取當(dāng)前登錄用戶的信息,只需要這樣做:

ws.send(JSON.stringify({obj: 'user', act: 'getMe'}));

Socket 服務(wù)器也支持頁(yè)面判斷功能,需要客戶端發(fā)送數(shù)據(jù)時(shí)同時(shí)發(fā)送 HTTP_REFERER 為當(dāng)前 URL 地址給服務(wù)器(自定義來路頁(yè)面)。例如上面獲取當(dāng)前用戶信息的例子,可以這樣:

ws.send(JSON.stringify({obj: 'user', act: 'getMe', HTTP_REFERER: location.href}));

雖然,ModPHP 提供了非常便捷的搭建 Socket 服務(wù)器的方法,但是你必不可濫用它。例如,在一個(gè) HTML 頁(yè)面,你應(yīng)該只設(shè)置一個(gè)指向同一服務(wù)器的 WebSocket 的實(shí)例。更好的就是,使用 iframe 等方式,實(shí)現(xiàn)多個(gè)頁(yè)面使用同一個(gè) WebSocket 實(shí)例。這樣可以有效地節(jié)約服務(wù)器資源,從而加快網(wǎng)站運(yùn)行速度。

其他客戶端類型連接服務(wù)器:

其他客戶端類型或者其他編程語言編寫得 Socket 客戶端的連接和通訊與 WebSocket 大同小異,但和 WebSocket 協(xié)議相比,這些客戶端不需要使用復(fù)雜的編碼和解碼過程,直接發(fā)送原始報(bào)文即可。

ModPHP 提供了在 Socket 服務(wù)器下進(jìn)行網(wǎng)站地址判斷的功能(如果網(wǎng)站地址未固定),這個(gè)特性,是依賴客戶端發(fā)送的握手包來實(shí)現(xiàn)的。在 WebSocket 協(xié)議中,客戶端會(huì)將一個(gè) HTTP 請(qǐng)求頭作為握手包發(fā)送給服務(wù)器。ModPHP 利用這個(gè)請(qǐng)求頭,來計(jì)算出網(wǎng)站的 URL 地址。

因此,你也可以在普通的 Socket 連接中,發(fā)送一個(gè) HTTP 請(qǐng)求頭格式的數(shù)據(jù),作為握手包,來讓服務(wù)器自動(dòng)“計(jì)算”網(wǎng)站的 URL 地址。

將 WebSocket 運(yùn)行于多線程中:

請(qǐng)查看《將 Socket 服務(wù)器運(yùn)行于多線程環(huán)境中》。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)