天天看點

使用php+swoole對client資料實時更新(二) (轉)

上一篇提到了swoole的基本使用,現在通過幾行基本的語句來實作比較複雜的邏輯操作:

先說一下業務場景。我們目前的大多數應用都是以服務端+接口+用戶端的方式去協調工作的,這樣的好處在于不論是處在何種終端的情況下,都可以完美的和服務端相容。這樣就輕松實作了MVC各個部分的真正解耦。但是提高程式的友好性還是有很多路要走,其中一個大家都會遇到的就是資料實時更新的問題。比如一個使用者在手機上做了添加操作,這時候其他的終端也應該及時顯示資料的變化情況。這個對于手機來說還算好辦,因為現在的各種推送服務完全可以滿足需求,當收到推送更新時,根據推送内容請求相應接口就可以了。但是放到PC上就不是這麼回事了。浏覽器和http協定的特殊性質不得不讓我們另辟蹊徑。

舉一個大家生活中都會遇到的場景:

某個周末你想要和女朋友去看一場電影,你在自己的pc上找到了某場的場次和座位。正當你要下單支付時,系統提示該座位已經售出,這時你不得不重新回到選座頁面重新挑選。那如果改進一下産品體驗,當有别的使用者已經購買某個座位的時候,浏覽器會及時将座位辨別已售出,這樣你就不用來回操作,節省操作時間。

** 針對上述的情景呢,這裡有一個系統間互動的流程圖:**

使用php+swoole對client資料實時更新(二) (轉)

上面一行就是使用系統的目前使用者,他對資料進行了相關操作,同時傳回操作結果

下面一行是其他使用者也正在操作同一條資料。當①(綠色)傳回結果時,web伺服器會同時告訴目前使用者和redis隊列服務(①黃色),因為websocket服務實時監聽redis,這樣一旦有資料變化,websocket服務會及時感覺。此時通過與浏覽器建立的長連接配接進行通訊并告知資料已經更新并重新加載。

另外一種方式是當①(綠色)傳回結果時不告訴redis隊列,而是直接通訊websocket服務資料已經發生變化,再由websocket服務通知浏覽器用戶端重新加載。因為此種方案比較簡單再加上swoole對一些操作的封裝比較便利,這裡就采用此種辦法

當websocket連接配接被打開時,向socket服務發送目前注冊id,因為隻有這樣websocket服務才能定向的為指定連接配接發送資料

當websocket服務收到注冊id時會将目前連接配接的id和由服務端傳來的商戶id對應關系寫入redis

因為swoole_websocket_server 繼承自 swoole_http_server ,這樣就可以通過http的方式和websocket服務進行互動

** 需要強調的一點是監聽http請求的server并不具備push方法,是以這裡通過全局變量的方式使用websocket的$server來向用戶端發送資料 **

以上就是解決問題的大概思路了,文章最後會附上websocket的服務端源碼,因為業務稍多是以裡面內建了很多業務代碼,而且需要運作起來必須要先安裝swoole的擴充,安裝方式上篇文章會有說明,是以這裡僅供參考
對于圖中另一種使用redis的方式也是很好的,之前采用了redis釋出訂閱的模式基本可以達到想要的效果。但是中間遇到一個問題redis的subscribe運作幾十秒後,就會抛出一個RedisException。原因處在于,php的redis庫使用的subscribe是使用PHP内置的socket,而php.ini預設是設定了socket的逾時時間是60秒,是以大家隻要找到default_socket_timeout 這個配置項,把時間改長點就可以了。或者在代碼中加入ini_set('default_socket_timeout', -1);

<a href="http://files.cnblogs.com/files/JasonLeemz/socket.zip">websocket服務端源碼</a>

http://www.cnblogs.com/JasonLeemz/p/5116814.html