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><span>html</span>></span><span>head</span>><span>meta</span><span>charset</span>=<span>"utf-8"</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>script</span><span>type</span>=<span>"text/javascript"</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>body</span>><span>div</span><span>id</span>=<span>"sse"</span>><span>a</span><span>href</span>=<span>"javascript:WebSocketConn()"</span>>进入聊天室<span><span>a</span>></span> <span>a</span><span>href</span>=<span>"javascript:WebSocketClose()"</span>>离开聊天室<span><span>a</span>></span><span>br</span>><span>br</span>><span>input</span><span>id</span>=<span>"msgtext"</span><span>type</span>=<span>"text"</span>><span>br</span>><span>a</span><span>href</span>=<span>"javascript:SendMsg()"</span>>发送信息<span><span>a</span>></span><span>br</span>><span>ol</span><span>id</span>=<span>"log"</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教程有兴趣的朋友有所帮助。

PHPsessionscanstorestrings,numbers,arrays,andobjects.1.Strings:textdatalikeusernames.2.Numbers:integersorfloatsforcounters.3.Arrays:listslikeshoppingcarts.4.Objects:complexstructuresthatareserialized.

TostartaPHPsession,usesession_start()atthescript'sbeginning.1)Placeitbeforeanyoutputtosetthesessioncookie.2)Usesessionsforuserdatalikeloginstatusorshoppingcarts.3)RegeneratesessionIDstopreventfixationattacks.4)Considerusingadatabaseforsessionstoragei

Session regeneration refers to generating a new session ID and invalidating the old ID when the user performs sensitive operations in case of session fixed attacks. The implementation steps include: 1. Detect sensitive operations, 2. Generate new session ID, 3. Destroy old session ID, 4. Update user-side session information.

PHP sessions have a significant impact on application performance. Optimization methods include: 1. Use a database to store session data to improve response speed; 2. Reduce the use of session data and only store necessary information; 3. Use a non-blocking session processor to improve concurrency capabilities; 4. Adjust the session expiration time to balance user experience and server burden; 5. Use persistent sessions to reduce the number of data read and write times.

PHPsessionsareserver-side,whilecookiesareclient-side.1)Sessionsstoredataontheserver,aremoresecure,andhandlelargerdata.2)Cookiesstoredataontheclient,arelesssecure,andlimitedinsize.Usesessionsforsensitivedataandcookiesfornon-sensitive,client-sidedata.

PHPidentifiesauser'ssessionusingsessioncookiesandsessionIDs.1)Whensession_start()iscalled,PHPgeneratesauniquesessionIDstoredinacookienamedPHPSESSIDontheuser'sbrowser.2)ThisIDallowsPHPtoretrievesessiondatafromtheserver.

The security of PHP sessions can be achieved through the following measures: 1. Use session_regenerate_id() to regenerate the session ID when the user logs in or is an important operation. 2. Encrypt the transmission session ID through the HTTPS protocol. 3. Use session_save_path() to specify the secure directory to store session data and set permissions correctly.

PHPsessionfilesarestoredinthedirectoryspecifiedbysession.save_path,typically/tmponUnix-likesystemsorC:\Windows\TemponWindows.Tocustomizethis:1)Usesession_save_path()tosetacustomdirectory,ensuringit'swritable;2)Verifythecustomdirectoryexistsandiswrita


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

SublimeText3 Linux new version
SublimeText3 Linux latest version

SublimeText3 Chinese version
Chinese version, very easy to use

Dreamweaver CS6
Visual web development tools

EditPlus Chinese cracked version
Small size, syntax highlighting, does not support code prompt function

WebStorm Mac version
Useful JavaScript development tools
