啟用 Socket 服務器

2018-06-13 15:41 更新

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

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

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

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

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

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

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

重現(xiàn)會話:


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

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

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)會話或者使用 WebSocket 進行登錄之后,之后的其他操作就已經(jīng)運行在已登錄狀態(tài)了,服務器會保存登錄信息,不需要客戶端再提交 Session ID。例如,要獲取當前登錄用戶的信息,只需要這樣做:

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

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

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

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

其他客戶端類型連接服務器:

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

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

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

將 WebSocket 運行于多線程中:

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

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號