Fork me on GitHub
随笔 - 193  文章 - 12  trackbacks - 0
<2018年5月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789


专注即时通讯及网游服务端编程
------------------------------------
本博收藏大部分文章为转载,并在文章开头给出了原文出处,如有再转,敬请保留相关信息,这是大家对原创作者劳动成果的自觉尊重!!如为您带来不便,请于本博下留言,谢谢配合。

常用链接

留言簿

随笔分类

随笔档案

相册

Awesome

Blog

Book

GitHub

Link

搜索

  •  

积分与排名

  • 积分 - 43492
  • 排名 - 407

最新评论

阅读排行榜

https://blog.csdn.net/orangleliu/article/details/50898014

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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

lua代码

-- simple chat with redis
local server = require "resty.websocket.server"
local redis = require "resty.redis"

local channel_name = "chat"
local msg_id = 0

--create connection
local wb, err = server:new{
  timeout = 10000,
  max_payload_len = 65535
}

--create success
if not wb then
  ngx.log(ngx.ERR, "failed to new websocket: ", err)
  return ngx.exit(444)
end


local push = function()
    -- --create redis
    local red = redis:new()
    red:set_timeout(5000) -- 1 sec
    local ok, err = red:connect("127.0.0.1", 6379)
    if not ok then
        ngx.log(ngx.ERR, "failed to connect redis: ", err)
        wb:send_close()
        return
    end

    --sub
    local res, err = red:subscribe(channel_name)
    if not res then
        ngx.log(ngx.ERR, "failed to sub redis: ", err)
        wb:send_close()
        return
    end

    -- loop : read from redis
    while true do
        local res, err = red:read_reply()
        if res then
            local item = res[3]
            local bytes, err = wb:send_text(tostring(msg_id).." "..item)
            if not bytes then
                -- better error handling
                ngx.log(ngx.ERR, "failed to send text: ", err)
                return ngx.exit(444)
            end
            msg_id = msg_id + 1
        end
    end
end


local co = ngx.thread.spawn(push)

--main loop
while true do
    -- 获取数据
    local data, typ, err = wb:recv_frame()

    -- 如果连接损坏 退出
    if wb.fatal then
        ngx.log(ngx.ERR, "failed to receive frame: ", err)
        return ngx.exit(444)
    end

    if not data then
        local bytes, err = wb:send_ping()
        if not 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" then
        break
    elseif typ == "ping" then
        local bytes, err = wb:send_pong()
        if not bytes then
            ngx.log(ngx.ERR, "failed to send pong: ", err)
            return ngx.exit(444)
        end
    elseif typ == "pong" then
        ngx.log(ngx.ERR, "client ponged")
    elseif typ == "text" then
        --send to redis
        local red2 = redis:new()
        red2:set_timeout(1000) -- 1 sec
        local ok, err = red2:connect("127.0.0.1", 6379)
        if not ok then
            ngx.log(ngx.ERR, "failed to connect redis: ", err)
            break
        end
        local res, err = red2:publish(channel_name, data)
        if not res then
            ngx.log(ngx.ERR, "failed to publish redis: ", err)
        end
    end
end

wb:send_close()
ngx.thread.wait(co)


3 页面代码

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <script type="text/javascript">
    
var ws = null;

    
function WebSocketConn() {
        
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!");
        }
    }

    
function SendMsg() {
        
if (ws != null && ws.readyState == 1) {
            
var msg = document.getElementById('msgtext').value;
            ws.send(msg);
        } 
else {
            log('请先进入聊天室');
        }
    }

    
function WebSocketClose() {
        
if (ws != null && ws.readyState == 1) {
            ws.close();
            log(
"发送断开服务器请求");
        } 
else {
            log(
"当前没有连接服务器")
        }
    }

    
function log(text) {
        
var li = document.createElement('li');
        li.appendChild(document.createTextNode(text));
        document.getElementById('log').appendChild(li);
        
return false;
    }
    
</script>
</head>

<body>
    <div id="sse">
        <href="javascript:WebSocketConn()">进入聊天室</a> &nbsp;
        <href="javascript:WebSocketClose()">离开聊天室</a>
        <br>
        <br>
        <input id="msgtext" type="text">
        <br>
        <href="javascript:SendMsg()">发送信息</a>
        <br>
        <ol id="log"></ol>
    </div>
</body>

</html>

4 效果

用iphone试了试,不好使,可能是websocket版本实现的问题。pc端测试可以正常使用。

这里写图片描述

Reading

posted on 2018-05-04 12:03 思月行云 阅读(32) 评论(0)  编辑 收藏 引用 所属分类: Nginx\Openresty

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理