cosocket 是各种 lua-resty-* 非阻塞库的基础
cosocket = coroutine + socket
需要 Lua 协程特性的支持,也需要 Nginx 事件机制的支持,两者结合在一起实现非阻塞网络 I/O。
遇到网络 I/O 时会交出控制权,把网络事件注册到 Nginx 监听列表中,并把权限交给 Nginx;当有 Nginx 事件到达触发条件时,便唤醒对应的协程继续处理。
cosocket API
TCP 相关 API
- 创建对象
ngx.socket.tcp
- 设置超时
tcpsock:settimeout
和tcpsock:settimeouts
- 建立连接
tcpsock:connect
- 发送数据
tcpsock:send
- 接收数据
tcpsock:receive
、tcpsock:receiveany
和tcpsock:receiveuntil
- 连接池
tcpsock:setkeepalive
- 关闭连接
tcpsock:close
由于 Nginx 内核的限制,cosocket API 在 set_by_lua, log_by_lua, header_filter_by_lua*,init_by_lua*,init_worker_by_lua* 和 body_filter_by_lua* 阶段中是无法使用的。**
与上面 API 相关的 Nginx 指令
lua_socket_connect_timeout
连接超时,默认 60slua_socket_send_timeout
发送超时,默认 60slua_socket_send_lowat
发送阈值,默认 0lua_socket_read_timeout
读取超时,默认 60slua_socket_buffer_size
读取数据的缓存区大小,默认 4k/8klua_socket_pool_size
连接池大小,默认 30lua_socket_keepalive_timeout
连接池 cosocket 对象的空闲时间,默认 60slua_socket_log_errors
cosocket 发生错误时是否记录日志,默认 no
当指令和 API 冲突时,API 会覆盖指令。
$ 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.1\r\nHost: www.baidu.com\r\n\r\n"
local bytes, err = sock:send(req_data)
if err then
ngx.say("failed to send: ", err)
return
end
local data, err, partial = sock:receive()
if err then
ngx.say("failed to receive: ", err)
return
end
sock:close()
ngx.say("response is: ", data)'
- 通过
ngx.socket.tcp()
创建名为 sock 的 TCP cosocket 对象 settimeout()
设置超时时间 1sconnect()
与指定网站建立 TCP 连接- 连接成功的话,用
send()
来发送数据,发送失败就退出 - 发送成功的话,用
receive()
来接收网站返回的数据 - 最后调用
close()
主动关闭 TCP 连接
连接池使用
- 不能把错误的连接放入连接池,否则下次使用时会导致收发数据失败(需要事先判断每个 API 调用是否成功)
- 要搞清楚连接的数据,连接池是 worker 级别的