主动通知客户端~!!

427 views
Skip to first unread message

borli...@gmail.com

unread,
Nov 22, 2013, 6:28:26 AM11/22/13
to openresty
hi all:
 
我是新手,问下大家
关于openResy服务器;有没有实现主动通知给客户端的,如果不采用轮询的方法;
 
我想用 ngx.req.socket()  连接到我自己的写得网关服务器。在openresty通知给 网关。网关在到客户端上去。。不知道这种方法可行,性能如何?
 
 
或者是否有websocket支持呢? 如果启用websocket; 在哪个版本中?
 
谢谢了~!
 
 
 

王斌科

unread,
Nov 22, 2013, 7:47:23 AM11/22/13
to open...@googlegroups.com
你好,有websocket支持的,具体可以看https://github.com/agentzh/lua-resty-websocket


--
--
邮件来自列表“openresty”,专用于技术讨论!
订阅: 请发空白邮件到 openresty...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+...@googlegroups.com
归档: http://groups.google.com/group/openresty
官网: http://openresty.org/
仓库: https://github.com/agentzh/ngx_openresty
教程: http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html

wgm

unread,
Nov 22, 2013, 7:53:57 AM11/22/13
to open...@googlegroups.com
websocket 好像无法做到服务器推送指定信息到指定客户端,只能做广播。

Yichun Zhang (agentzh)

unread,
Nov 22, 2013, 2:49:06 PM11/22/13
to openresty
Hello!

2013/11/22 wgm:
> websocket 好像无法做到服务器推送指定信息到指定客户端,只能做广播。
>

这种说法不对。WebSocket 只是一种全双工的增强版的 http 协议,至于服务器端的数据流如何管理,那是上层应用的事情。

Regards,
-agentzh

YuLei Liao

unread,
Nov 22, 2013, 8:55:34 PM11/22/13
to open...@googlegroups.com
完全可以!

> 在 2013年11月22日,20:53,wgm <wgm....@gmail.com> 写道:
>
> websocket 好像无法做到服务器推送指定信息到指定客户端,只能做广播。
>

borli...@gmail.com

unread,
Nov 22, 2013, 9:53:49 PM11/22/13
to YuLei Liao, open...@googlegroups.com
手游这块~ 我想让 http 和 websocket 共存;
这样的方式会有什么问题吗?? 用redis做数据的存储当状态; 游戏的逻辑用http。。
战斗中采用websocket。。 不知道这样有产生什么问题
没试验过。。呵呵。希望大神们能给点建议
    server {
        listen 8080;
        #lua_socket_buffer_size 8k;
        #lua_socket_pool_size 30;
       #游戏逻辑短连接
        location /ddz {
            default_type  application/octet-stream;
            content_by_lua_file lua/bin/ddz.lua ;
            #lua_code_cache off;
      }
      #战斗过程长连接
        location /ws {
            content_by_lua_file lua/gateserver.lua ;
            #lua_code_cache off;
        }
   
 

 
发件人: YuLei Liao
发送时间: 2013-11-23 09:55
主题: Re: [openresty] 主动通知客户端~!!
完全可以!
 
> 在 2013年11月22日,20:53,wgm <wgm....@gmail.com> 写道:
>
> websocket 好像无法做到服务器推送指定信息到指定客户端,只能做广播。
>
 

Yichun Zhang (agentzh)

unread,
Nov 22, 2013, 10:27:22 PM11/22/13
to openresty
Hello!

On Fri, Nov 22, 2013 at 6:53 PM, borlinmanbu wrote:
> 手游这块~ 我想让 http 和 websocket 共存;
> 这样的方式会有什么问题吗??

不会,因为是不同的连接。

> 用redis做数据的存储当状态; 游戏的逻辑用http。。
> 战斗中采用websocket。。 不知道这样有产生什么问题

技术上是不会有问题的。如果有问题,欢迎报告。

Regards,
-agentzh

borli...@gmail.com

unread,
Nov 24, 2013, 12:59:13 AM11/24/13
to openresty
 
你好!
 
。。就是服务端要主动 指定一个在线的玩家,给他发消息,怎么实现的呢???
 
我测试了下  用表 保存每个新来的websocket;
t[1001] = wb1
t[1002] = wb2
 
例如 服务端收到1001 客户端来消息 发送给 1002.。
  t[1002] :send_text("hello word !") 
出现 错误;fatal error already happened,
或者 soket busy  这样的错误!
 
本人第一次使用websocket。。还是不太了解机制 ~!
 

 
发送时间: 2013-11-23 03:49
收件人: openresty
主题: Re: [openresty] 主动通知客户端~!!

YuLei Liao

unread,
Nov 24, 2013, 1:19:03 AM11/24/13
to open...@googlegroups.com
要打一个补丁才行。

把我以前的一个主题内容转上来

---------

我们是做手游的团队,最近一款游戏有不少实时性,正好看到 OpenResty 已经支持了 WebSockets,所以基于 OpenResty 设计了一个 game server 架构。

PS: 选择 OpenResty 的原因是我们前一款游戏也是用的 OpenResty,感觉很不错(虽然最后游戏没有挣到钱)。


整体架构图:



内嵌图片 1



几点说明:

1. 因为现在版本的 cosocket 还不支持同时读写,所以我使用了这个补丁 https://github.com/aviramc/lua-nginx-module/tree/socket-changes
2. redis 是主数据库,日志类数据则存入 mysql,图里没有画出来

----

整个架构的重点有三部分:请求/响应模型,使用 redis 做消息转发,使用 job server 执行延时任务

1. 请求/响应模型

客户端通过 websockets 发送消息给服务端。每个消息都是 JSON 格式。其中包含 action 和 msgid 两个必须的参数。

- action 用于指示要调用服务端哪一个消息处理函数。例如 action = users.auth 就表示要调用服务端 UsersAction 模块的 authAction 方法。
- msgid 用于跟踪消息的执行结果,每一个从客户端发往服务端的消息都会带有一个 msgid(累加值)。当服务端的消息处理函数执行后,通过 websockets 发送消息到客户端,其中会包含请求消息中的 msgid。这样客户端就可以知道从服务端发来的消息是属于先前哪一个请求的反馈。这样模拟了 HTTP 的请求/响应模型,简化了客户端的代码实现。


2. 使用 redis 做消息转发

因为现在没有办法从外部取得一个线程的 cosocket 对象,所以也就无法直接向任意客户端发送消息。为了解决这个问题,我利用 redis 的 pub/sub 特性,实现了一个简单的消息中转机制。

每一个客户端连接到 OpenResty 后,就会创建一个子线程(ngx.thread.spawn)。这个子线程会创建一个 redis 连接,并 subscribechannel.id(连接成功的客户端都有一个自己的频道)。当有任何消息进入频道,这个子线程就通过主线程的 cosocket 对象将消息发往客户端(这里就需要前面提到的 cosocket 补丁)。


3. 使用 job server 执行延时任务

选择 beanstalkd 是因为有现成的 lua-resty-beanstalkd 模块,用起来省事儿。而且 beanstalkd 也支持延时消息,非常适合我们游戏中的需求。比如升级一个建筑物需要 10 分钟,那么我添加一个延时 10 分钟的消息到 beanstalkd 里就行了。

当一个消息倒计时结束时,就会由 worker 负责处理消息。worker 取得消息后,进行处理。如果处理后需要将更新后的数据发送到客户端,就通过 redis publish 命令来进行了。

Yichun Zhang (agentzh)

unread,
Nov 24, 2013, 3:16:56 PM11/24/13
to openresty
Hello!

2013/11/23 borlinmanbu:
>
> 我测试了下 用表 保存每个新来的websocket;
> t[1001] = wb1
> t[1002] = wb2
>

这种用法是错误的。

websocket 对象本质上也是 cosocket 对象。而根据目前 ngx_lua 模块的实现,cosocket
对象是不能在当前请求的范围之外使用的。所以通过 Lua 变量在不同的请求之间直接传递 cosocket
对象会导致未定义的行为,应当绝对避免。

你只能通过 Lua 变量在请求之间传递普通的 Lua 值。不过,即使你通过 Lua 变量来在请求之间传递值,你也只能在同一个 nginx
worker 进程服务的请求之间传递,毕竟不同的 nginx worker 进程都有自己独立的 Lua VM 实例和自己独立的进程空间。

一般建议使用共享内存字典来在请求之间共享和传递数据,毕竟共享内 存是当前的 nginx 服务器实例中的所有 nginx worker 进程共享的,见

https://github.com/chaoslawful/lua-nginx-module#lua_shared_dict

不过,值得提醒的是,如果你有多台前端机或者多个独立的 nginx 服务器实例,则共享内存字典也是不能跨域机器的边界或者 nginx
服务器实例(即 master-worker 进程组)的边界的。你需要借助于外部像 redis 这样的共享数据服务,或者自己做
sharding.

> 例如 服务端收到1001 客户端来消息 发送给 1002.。
> t[1002] :send_text("hello word !")
> 出现 错误;fatal error already happened,

这个错误一般是因为你之前的某一次操作没有进行恰当的错误处理,你的 Lua 代码继续尝试使用已经出现致命错误的 websocket 对象。

> 或者 soket busy 这样的错误!
>

这个错误是一般是当你有多个请求(或者多个轻量级线程)同时访问同一个 cosocket 对象时抛出的。你应当自己避免这种不正确的用法。

Regards,
-agentzh

Yichun Zhang (agentzh)

unread,
Nov 24, 2013, 3:19:53 PM11/24/13
to openresty
Hello!

2013/11/23 YuLei Liao
>
> 要打一个补丁才行。
>

你说的这个给 cosocket 添加完整的全双工支持的补丁只是允许一个轻量级线程在读取某个 cosocket
对象的同时,允许同一个请求内的另一个轻量级线程写这个 cosocket 对象。而 cosocket
对象的使用范围仍然局限在创建它的请求范围内 :)

Regards,
-agentzh

dualface

unread,
Nov 25, 2013, 9:51:46 AM11/25/13
to open...@googlegroups.com
能够双工已经完全满足需求了,至于跨线程的 cosocket 对象我倒觉得没必要,太容易搞出查不到来源的 bug 了。

PS: 今天正好有开发者报告了这个补丁的一个 bug。启用这个补丁后,mysql 连接时会提示:

resty/mysql.lua:504: bad argument #3 to 'connect' (bad "ssl" option type: nil)

去掉这个补丁则完全 OK。看来这个补丁的改动导致了一些其他问题。

不过我还是期待早日合并这个全双工补丁,因为没有这个的话,一些功能就无法实现。

Yichun Zhang (agentzh)

unread,
Nov 25, 2013, 2:00:12 PM11/25/13
to openresty
Hello!

2013/11/25 dualface:
>
> 能够双工已经完全满足需求了,至于跨线程的 cosocket 对象我倒觉得没必要,太容易搞出查不到来源的 bug 了。
>

嗯 :)

> PS: 今天正好有开发者报告了这个补丁的一个 bug。启用这个补丁后,mysql 连接时会提示:
>
> resty/mysql.lua:504: bad argument #3 to 'connect' (bad "ssl" option type:
> nil)
>
> 去掉这个补丁则完全 OK。看来这个补丁的改动导致了一些其他问题。
>

你能在那个 pull request 里面评论吗?这样 Aviram 同学或许可以帮着看一眼 :)

另外,值得一提的是,那个补丁里有很多和全双工不相关的功能,比如 SSL cosocket 支持和 BSD recv()
支持。你可以自己去掉那些部分。比如你上面这个错误显然是 SSL 部分的问题。

> 不过我还是期待早日合并这个全双工补丁,因为没有这个的话,一些功能就无法实现。
>

嗯嗯,我得加快这个补丁的 review 和 merge 工作!:)

Best regards,
-agentzh
Reply all
Reply to author
Forward
0 new messages