Hello!
2015-02-13 1:53 GMT-08:00 home_king:
> 我看过ngx_lua的文档,也看过代码(代码比较复杂),我对cosocket的receiveuntil还是很困惑。
> 它所返回的iterator应该是匹配到pattern或者error就返回匹配开始点之前的字符串(假设inclusive==nil),对吧?
默认的参数下是这样的行为,但可以通过参数动态配置。
> 但如果iterator带上一个size参数,就有以下问题了:
> 1. 假设匹配到pattern之前,字符串很长,例如1MB,那是不是没匹配到之前,都缓存所有输入呢?
不会缓存所有数据。这是流式处理模式。lua-resty-upload 库正是利用这个特性实现严格非缓存的 multipart 上传数据流的读取和解析。
> 2. 如果缓存,那么这个缓存上限不应该是无限大,但如果不是无限大,又不知道输入究竟有多长,这是一个矛盾啊。
缓存的数据量大小取决于这个 size 参数值以及 lua_socket_buffer_size 指令的配置值的较大者。
> 3.
> 如果不缓存,在没匹配到之前只是返回size个字节,那又有一个问题了,假设某个状态字符串是"abc---c",而pattern是"---cdef",这时候size=10,那就会返回整个字符串给caller了,这时候系统里面的字符串就被清空了,后面又收到输入为"def232",本来如果不清空还可以匹配的,而现在就不行了。那就错失掉一次匹配了。如果settimeout,那就更复杂了,超时后还要返回partial,那就只能清空,那这个问题怎么办?
receiveuntil 函数的实现内置了一个简化的 DFA
状态机构造器,它会自动处理有歧义的情形而不用在输入流中进行回溯。所以“清空”只适用于无歧义的数据流部分。对于你的例子,只会返回
abc,因为后面的 ---c 是有歧义的,除非已经看到了输入流的末尾(此时无歧义)。
> 4. 另外一个问题就是如果创建多个receiveuntil的iterator
> function,交错执行,那是不是就会使得匹配过程互相干扰而错乱了呢?因为如果要解决这个问题,就需要每个iterator都缓存输入的副本才能做到互不干扰,但我想这样内存会耗得多,尤其是考虑到第1点。
>
iterator 的特性就是自含状态,这利用了 Lua 的闭包特性,状态数据通过 upvalue 隐含在了 iterator
内部,所以不至相互冲突。注意这里并不需要复制输入流数据,因为输入缓冲区就一个,张三读了某段数据,李四就只能读后面的数据了。
建议加入 openresty 中文邮件列表讨论这样的问题,谢谢合作!见 http://openresty.org/#Community 同时抄送给该列表。
Regards,
-agentzh