openresty+websocket+redis simple chat

來源:互聯網
上載者:User

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地址。

配置片段

    location = /sredis {        content_by_lua_file conf/lua/ws_redis.lua;    }    location ~ /ws/(.*) {        alias conf/html/$1.html;    }

lua代碼

-- simple chat with redislocal server = require"resty.websocket.server"local redis = require"resty.redis"local channel_name = "chat"local msg_id = 0--create connectionlocal wb, err = server:new{  timeout = 10000,  max_payload_len = 65535}--create successifnot wb then  ngx.log(ngx.ERR, "failed to new websocket: ", err)  return ngx.exit(444)endlocal push = function()-- --create redislocal red = redis:new()    red:set_timeout(5000) -- 1 seclocal ok, err = red:connect("127.0.0.1", 6379)    ifnot ok then        ngx.log(ngx.ERR, "failed to connect redis: ", err)        wb:send_close()        returnend--sublocal res, err = red:subscribe(channel_name)    ifnot res then        ngx.log(ngx.ERR, "failed to sub redis: ", err)        wb:send_close()        returnend-- loop : read from rediswhiletruedolocal res, err = red:read_reply()        if res thenlocal item = res[3]            local bytes, err = wb:send_text(tostring(msg_id).." "..item)            ifnot bytes then-- better error handling                ngx.log(ngx.ERR, "failed to send text: ", err)                return ngx.exit(444)            end            msg_id = msg_id + 1endendendlocal co = ngx.thread.spawn(push)--main loopwhiletruedo-- 擷取資料local data, typ, err = wb:recv_frame()    -- 如果串連損壞 退出if wb.fatal then        ngx.log(ngx.ERR, "failed to receive frame: ", err)        return ngx.exit(444)    endifnot data thenlocal bytes, err = wb:send_ping()        ifnot bytes then          ngx.log(ngx.ERR, "failed to send ping: ", err)          return ngx.exit(444)        end        ngx.log(ngx.ERR, "send ping: ", data)    elseif typ == "close"thenbreakelseif typ == "ping"thenlocal bytes, err = wb:send_pong()        ifnot bytes then            ngx.log(ngx.ERR, "failed to send pong: ", err)            return ngx.exit(444)        endelseif typ == "pong"then        ngx.log(ngx.ERR, "client ponged")    elseif typ == "text"then--send to redislocal red2 = redis:new()        red2:set_timeout(1000) -- 1 seclocal ok, err = red2:connect("127.0.0.1", 6379)        ifnot ok then            ngx.log(ngx.ERR, "failed to connect redis: ", err)            breakendlocal res, err = red2:publish(channel_name, data)        ifnot res then            ngx.log(ngx.ERR, "failed to publish redis: ", err)        endendendwb:send_close()ngx.thread.wait(co)

3 頁面代碼

<html><head><metacharset="utf-8"><metaname="viewport"content="width=device-width, initial-scale=1.0, user-scalable=no"><scripttype="text/javascript">var ws = null;    functionWebSocketConn() {if (ws != null && ws.readyState == 1) {            log("已經線上");            return        }        if ("WebSocket"in window) {            // Let us open a web socket            ws = new WebSocket("ws://localhost:8008/sredis");            ws.onopen = function() {                log('成功進入聊天室');            };            ws.onmessage = function(event) {                log(event.data)            };            ws.onclose = function() {// websocket is closed.                log("已經和伺服器斷開");            };            ws.onerror = function(event) {                console.log("error " + event.data);            };        } else {            // The browser doesn't support WebSocket            alert("WebSocket NOT supported by your Browser!");        }    }    functionSendMsg() {if (ws != null && ws.readyState == 1) {            var msg = document.getElementById('msgtext').value;            ws.send(msg);        } else {            log('請先進入聊天室');        }    }    functionWebSocketClose() {if (ws != null && ws.readyState == 1) {            ws.close();            log("發送斷開伺服器請求");        } else {            log("當前沒有串連伺服器")        }    }    functionlog(text) {var li = document.createElement('li');        li.appendChild(document.createTextNode(text));        document.getElementById('log').appendChild(li);        returnfalse;    }    script>head><body><divid="sse"><ahref="javascript:WebSocketConn()">進入聊天室a>          <ahref="javascript:WebSocketClose()">離開聊天室a><br><br><inputid="msgtext"type="text"><br><ahref="javascript:SendMsg()">發送資訊a><br><olid="log">ol>div>body>html>

4 效果

用iphone試了試,不好使,可能是websocket版本實現的問題。pc端測試可以正常使用。

Reading

  • 郵件清單討論 websocket chat
  • Aapo Websocket with openresty

').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('
  • ').text(i)); }; $numbering.fadeIn(1700); }); });

    以上就介紹了openresty+websocket+redis simple chat,包括了方面的內容,希望對PHP教程有興趣的朋友有所協助。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.