openresty+websocket+redis簡單聊天
openresty 很早就支持websocket了,但是早期的版本cosocket是单工的,处理起来比较麻烦参见邮件列表讨论 websocket chat,后来的版本cosocket是双全工的,就可以按照这个讨论的方案来实现基于websocket的聊天,或者是push程序了,但是网络上没有找到一个具体一点的例子,于是自己写了个simple的例子。
1 思路
client的websocket连接到openresty之后,使用ngx.thread.spawn
启动两个 轻线程
,一个用来接收客户端提交的数据往redis的channel写,另一个用来订阅channel,读取redis的数据写给客户端。channel相当于一个chat room,多个client一起订阅,有人发聊天信息(pub),所有人都能得到信息(sub)。代码比较简陋,简单的思路的实现。
2 服务端代码
依赖:
- openresty
- redis
- lua-resty-redis
- lua-resty-websocket 只支持RFC 6455
nginx的配置全贴了,就是两个location,一个是页面地址,一个是websocket地址。
配置片段
<code> location = /sredis <span>{ content_by_lua_file conf/lua/ws_redis.lua; }</span> location ~ /ws/(.*) <span>{ alias conf/html/$1.html; }</span></code>
lua代码
<code><span>-- simple chat with redis</span><span>local</span> server = <span>require</span><span>"resty.websocket.server"</span><span>local</span> redis = <span>require</span><span>"resty.redis"</span><span>local</span> channel_name = <span>"chat"</span><span>local</span> msg_id = <span>0</span><span>--create connection</span><span>local</span> wb, err = server:new{ timeout = <span>10000</span>, max_payload_len = <span>65535</span> } <span>--create success</span><span>if</span><span>not</span> wb <span>then</span> ngx.log(ngx.ERR, <span>"failed to new websocket: "</span>, err) <span>return</span> ngx.exit(<span>444</span>) <span>end</span><span>local</span> push = <span><span>function</span><span>()</span></span><span>-- --create redis</span><span>local</span> red = redis:new() red:set_timeout(<span>5000</span>) <span>-- 1 sec</span><span>local</span> ok, err = red:connect(<span>"127.0.0.1"</span>, <span>6379</span>) <span>if</span><span>not</span> ok <span>then</span> ngx.log(ngx.ERR, <span>"failed to connect redis: "</span>, err) wb:send_close() <span>return</span><span>end</span><span>--sub</span><span>local</span> res, err = red:subscribe(channel_name) <span>if</span><span>not</span> res <span>then</span> ngx.log(ngx.ERR, <span>"failed to sub redis: "</span>, err) wb:send_close() <span>return</span><span>end</span><span>-- loop : read from redis</span><span>while</span><span>true</span><span>do</span><span>local</span> res, err = red:read_reply() <span>if</span> res <span>then</span><span>local</span> item = res[<span>3</span>] <span>local</span> bytes, err = wb:send_text(<span>tostring</span>(msg_id)..<span>" "</span>..item) <span>if</span><span>not</span> bytes <span>then</span><span>-- better error handling</span> ngx.log(ngx.ERR, <span>"failed to send text: "</span>, err) <span>return</span> ngx.exit(<span>444</span>) <span>end</span> msg_id = msg_id + <span>1</span><span>end</span><span>end</span><span>end</span><span>local</span> co = ngx.thread.spawn(push) <span>--main loop</span><span>while</span><span>true</span><span>do</span><span>-- 获取数据</span><span>local</span> data, typ, err = wb:recv_frame() <span>-- 如果连接损坏 退出</span><span>if</span> wb.fatal <span>then</span> ngx.log(ngx.ERR, <span>"failed to receive frame: "</span>, err) <span>return</span> ngx.exit(<span>444</span>) <span>end</span><span>if</span><span>not</span> data <span>then</span><span>local</span> bytes, err = wb:send_ping() <span>if</span><span>not</span> bytes <span>then</span> ngx.log(ngx.ERR, <span>"failed to send ping: "</span>, err) <span>return</span> ngx.exit(<span>444</span>) <span>end</span> ngx.log(ngx.ERR, <span>"send ping: "</span>, data) <span>elseif</span> typ == <span>"close"</span><span>then</span><span>break</span><span>elseif</span> typ == <span>"ping"</span><span>then</span><span>local</span> bytes, err = wb:send_pong() <span>if</span><span>not</span> bytes <span>then</span> ngx.log(ngx.ERR, <span>"failed to send pong: "</span>, err) <span>return</span> ngx.exit(<span>444</span>) <span>end</span><span>elseif</span> typ == <span>"pong"</span><span>then</span> ngx.log(ngx.ERR, <span>"client ponged"</span>) <span>elseif</span> typ == <span>"text"</span><span>then</span><span>--send to redis</span><span>local</span> red2 = redis:new() red2:set_timeout(<span>1000</span>) <span>-- 1 sec</span><span>local</span> ok, err = red2:connect(<span>"127.0.0.1"</span>, <span>6379</span>) <span>if</span><span>not</span> ok <span>then</span> ngx.log(ngx.ERR, <span>"failed to connect redis: "</span>, err) <span>break</span><span>end</span><span>local</span> res, err = red2:publish(channel_name, data) <span>if</span><span>not</span> res <span>then</span> ngx.log(ngx.ERR, <span>"failed to publish redis: "</span>, err) <span>end</span><span>end</span><span>end</span>wb:send_close() ngx.thread.wait(co)</code>
3 页面代码
<code><span><!DOCTYPE HTML></span><span><<span>html</span>></span><span><<span>head</span>></span><span><<span>meta</span><span>charset</span>=<span>"utf-8"</span>></span><span><<span>meta</span><span>name</span>=<span>"viewport"</span><span>content</span>=<span>"width=device-width, initial-scale=1.0, user-scalable=no"</span>></span><span><<span>script</span><span>type</span>=<span>"text/javascript"</span>></span><span><span>var</span> ws = <span>null</span>; <span><span>function</span><span>WebSocketConn</span><span>()</span> {</span><span>if</span> (ws != <span>null</span> && ws.readyState == <span>1</span>) { log(<span>"已经在线"</span>); <span>return</span> } <span>if</span> (<span>"WebSocket"</span><span>in</span> window) { <span>// Let us open a web socket</span> ws = <span>new</span> WebSocket(<span>"ws://localhost:8008/sredis"</span>); ws.onopen = <span><span>function</span><span>()</span> {</span> log(<span>'成功进入聊天室'</span>); }; ws.onmessage = <span><span>function</span><span>(event)</span> {</span> log(event.data) }; ws.onclose = <span><span>function</span><span>()</span> {</span><span>// websocket is closed.</span> log(<span>"已经和服务器断开"</span>); }; ws.onerror = <span><span>function</span><span>(event)</span> {</span> console.log(<span>"error "</span> + event.data); }; } <span>else</span> { <span>// The browser doesn't support WebSocket</span> alert(<span>"WebSocket NOT supported by your Browser!"</span>); } } <span><span>function</span><span>SendMsg</span><span>()</span> {</span><span>if</span> (ws != <span>null</span> && ws.readyState == <span>1</span>) { <span>var</span> msg = document.getElementById(<span>'msgtext'</span>).value; ws.send(msg); } <span>else</span> { log(<span>'请先进入聊天室'</span>); } } <span><span>function</span><span>WebSocketClose</span><span>()</span> {</span><span>if</span> (ws != <span>null</span> && ws.readyState == <span>1</span>) { ws.close(); log(<span>"发送断开服务器请求"</span>); } <span>else</span> { log(<span>"当前没有连接服务器"</span>) } } <span><span>function</span><span>log</span><span>(text)</span> {</span><span>var</span> li = document.createElement(<span>'li'</span>); li.appendChild(document.createTextNode(text)); document.getElementById(<span>'log'</span>).appendChild(li); <span>return</span><span>false</span>; } </span><span></<span>script</span>></span><span></<span>head</span>></span><span><<span>body</span>></span><span><<span>div</span><span>id</span>=<span>"sse"</span>></span><span><<span>a</span><span>href</span>=<span>"javascript:WebSocketConn()"</span>></span>进入聊天室<span></<span>a</span>></span> <span><<span>a</span><span>href</span>=<span>"javascript:WebSocketClose()"</span>></span>离开聊天室<span></<span>a</span>></span><span><<span>br</span>></span><span><<span>br</span>></span><span><<span>input</span><span>id</span>=<span>"msgtext"</span><span>type</span>=<span>"text"</span>></span><span><<span>br</span>></span><span><<span>a</span><span>href</span>=<span>"javascript:SendMsg()"</span>></span>发送信息<span></<span>a</span>></span><span><<span>br</span>></span><span><<span>ol</span><span>id</span>=<span>"log"</span>></span><span></<span>ol</span>></span><span></<span>div</span>></span><span></<span>body</span>></span><span></<span>html</span>></span></code>
4 效果
用iphone试了试,不好使,可能是websocket版本实现的问题。pc端测试可以正常使用。
Reading
- 邮件列表讨论 websocket chat
- Aapo Websocket with openresty
以上就介绍了openresty+websocket+redis simple chat,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

隨著網路科技的不斷發展,即時通訊已經成為了日常生活中不可或缺的一部分。利用WebSockets技術可以實現高效、低延遲的即時通信,而PHP作為互聯網領域使用最廣泛的開發語言之一,也提供了相應的WebSocket支援。本文將為大家介紹如何使用PHP和WebSocket實現即時通信,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

隨著網路技術的不斷發展,即時視訊串流已成為了網路領域的重要應用。要實現即時視訊串流播放,其中的關鍵技術包括WebSocket和Java。本文將介紹如何結合使用WebSocket和Java實現即時視訊串流播放,並提供相關的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工通訊的協議,它在Web

golangWebSocket與JSON的結合:實現資料傳輸和解析在現代的Web開發中,即時資料傳輸變得越來越重要。 WebSocket是一種用於實現雙向通訊的協議,與傳統的HTTP請求-回應模型不同,WebSocket允許伺服器向客戶端主動推送資料。而JSON(JavaScriptObjectNotation)是一種用於資料交換的輕量級格式,它簡潔易讀

PHP和WebSocket:實現即時資料傳輸的最佳實踐方法引言:在Web應用程式開發中,即時資料傳輸是一項非常重要的技術需求。傳統的HTTP協定是一種請求-回應模式的協議,不能有效地實現即時資料傳輸。為了滿足即時資料傳輸的需求,WebSocket協定應運而生。 WebSocket是一種全雙工通訊協議,它提供了一種在單一TCP連接上進行全雙工通訊的方式。相比於H

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用Java和WebSocket實現即時股票行情推播引言:隨著網路的快速發展,股票行情即時推播成為了投資人關注的焦點之一。傳統的股票行情推送方式存在延遲較高、刷新速度慢等問題,對於投資人來說,無法及時獲得最新的股票行情資訊可能會導致投資決策的誤差。而基於Java和WebSocket的即時股票行情推送可以有效解決這個問題,使投資者能夠第一時間獲取到最新的

JavaWebsocket如何實現線上白板功能?在現代網路時代,人們越來越注重即時協作和互動的體驗。線上白板就是一種基於Websocket實現的功能,它能夠使多個使用者即時協作編輯同一個畫板,完成繪圖和標註等操作,為線上教育、遠端會議、團隊協作等場景提供了便捷的解決方案。一、技術背景WebSocket是HTML5提供的一種新的協議,它在同一條TCP連接上實
