-
创建对象:ngx.socket.tcp。
-
设置超时:tcpsock:settimeout 和 tcpsock:settimeouts。
-
建立连接:tcpsock:connect。
-
发送数据:tcpsock:send。
-
接受数据:tcpsock:receive、tcpsock:receiveany 和 tcpsock:receiveuntil。
-
连接池:tcpsock:setkeepalive。
-
关闭连接:tcpsock:close。
-
上下文:
rewrite
_by_lua
*,
access_by_lua*
,
content
_by_lua
*,
ngx.timer.*
,
ssl
_certificate_by
_lua*,
ssl_
session
_fetch_by
_lua*_
cosocket API 在 set_by_lua, log_by_lua, header_filter_by_lua* 和 body_filter_by_lua* 中是无法使用的。init_by_lua* 和 init_worker_by_lua* 中暂时也不能用。与这些API相应的Nginx指令:
-
lua_socket_connect_timeout:连接超时,默认 60 秒。
lua_socket_send_timeout:发送超时,默认 60 秒。
lua_socket_send_lowat:发送阈值(low water),默认为 0。
lua_socket_read_timeout:读取超时,默认 60 秒。
lua_socket_buffer_size:读取数据的缓存区大小,默认 4k/8k。
lua_socket_pool_size:连接池大小,默认 30。
lua_socket_keepalive_timeout:连接池 cosocket 对象的空闲时间,默认 60 秒。
lua_socket_log_errors:cosocket 发生错误时,是否记录日志,默认为 on。
$ resty -e 'local sock = ngx.socket.tcp()
sock:settimeout(1000) -- one second timeout
local ok, err = sock:connect("www.baidu.com", 80)
if not ok then
ngx.say("failed to connect: ", err)
return
end
local req_data = "GET / HTTP/1.1rnHost: www.baidu.comrnrn"
localbytes, err = sock:send(req_data)
if err then
ngx.say("failed to send: ", err)
return
end
localdata, err, partial = sock:receive()
if err then
ngx.say("failed to receive: ", err)
return
end
sock:close()
ngx.say("response is: ", data)
-
1、首先,通过 ngx.socket.tcp() ,创建 TCP 的 cosocket 对象,名字是 sock。 -
2、然后,使用 settimeout() ,把超时时间设置为 1 秒。注意这里的超时没有区分 connect、receive,是统一的设置。 -
3、接着,使用 connect() 去连接指定网站的 80 端口,如果失败就直接退出。 -
4、连接成功的话,就使用 send() 来发送构造好的数据,如果发送失败就退出。 -
5、发送数据成功的话,就使用 receive() 来接收网站返回的数据。这里 receive() 的默认参数值是 l,也就是只返回第一行的数据;如果参数设置为了a,就是持续接收数据,直到连接关闭; -
6、最后,调用 close() ,主动关闭 socket 连接。
在上面settimeout() 的作用是把连接、发送和读取超时时间统一设置为一个值。如果要想分开设置,就需要使用 settimeouts() 函数:
sock:settimeouts(1000, 2000, 3000)
receive 接收指定大小:
localdata, err, partial = sock:receiveany(10240)
这段代码就表示,最多只接收 10K 的数据。
关于 receive,还有另一个很常见的用户需求,那就是一直获取数据,直到遇到指定字符串才停止。
local reader = sock:receiveuntil("rn")
while true do
local data, err, partial = reader(4)
if not data then
if err then
ngx.say("failed to read the data stream: ", err)
break
end
ngx.say("read done")
break
end
ngx.say("read chunk: [", data, "]")
end
这段代码中的 receiveuntil 会返回 rn 之前的数据,并通过迭代器每次读取其中的 4 个字节。
连接池
没有连接池的话,每次请求进来都要新建一个连接,就会导致 cosocket 对象被频繁地创建和销毁,造成不必要的性能损耗。
在你使用完一个 cosocket 后,可以调用 setkeepalive() 放到连接池中:
local ok, err = sock:setkeepalive(2 * 1000, 100)
if not ok then
ngx.say("failed to set reusable: ", err)
end
这段代码设置了连接的空闲时间为 2 秒,连接池的大小为 100。在调用 connect() 函数时,就会优先从连接池中获取 cosocket 对象。
需注意:
1、不能把发生错误的连接放入连接池;
2、要搞清楚连接的数量。连接池是 worker 级别的,每个 worker 都有自己的连接池。所以,如果你有 10 个 worker,连接池大小设置为 30,那么对于后端的服务来讲,就等于有 300 个连接。
原文始发于微信公众号(安全防护):openresty协程
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论