大家好,在使用OpenResty 提供的cosocket在多线程中使用时,始终无法正确释放连接。
OpenResty版本号: openresty-1.19.9.1
我们的服务大致是这样的:
两个客户端A和B分别连接到OpenResty,OpenResty再将请求转发到后端服务.大致架构如下:
ClientA --
\
OpenResty--BackEnd
/
ClientB --
ClientA和ClientB都在各自内网,他们都作为TCP客户端连接公网OpenResty。
ClientA和B刚开始都进行一些信令交互,完成后开始传输业务(TCP/HTTP)数据。
业务数据完全是经过加密。
ClientA是作为TCP/HTTP客户端
ClientB是作为TCP/HTTP服务器端
(1). 有短连接,一次请求完成后,两端都各自关闭
(2). 短连接,请求完成后,ClientA关闭,然后BackEnd关闭。最终是希望OpenResty连接ClientB的套接字能正常关闭释放。从而ClientB也能释放
(3). 有长连接,一次请求完成后,两端都不关闭,后续接着使用
现在发现第二种情况下始终存在异常。造成ClientB连接OpenResty连接资源无法释放。
请大家帮忙看看这个cosocket API使用哪里不当?还是因为cosocket限制?
Lua 代码如下,在content_by_lua_file 阶段执行。
```
local SOCKET_BUFFER_SIZE = 4096
-- 代理端服务套接字
local clientSock = ngx.req.socket()
clientSock:settimeouts(3000, 36000000, 36000000)
-- 连接后端的套接字
local cloudSock = ngx.socket.tcp()
cloudSock:settimeouts(3000, 36000000, 36000000)
-- 连接后端服务
local ok, err = zrplSock:connect("127.0.0.1", DEFAULT_CLOUD_PORT)
-- 进行一些数据交互操作,读取完后,发送对端,不会篡改数据
-- (1). 读取clientSock一些字节, 提取信息
-- (2). 再将这些字节发给cloudSock
-- (3). cloudSock读取一些字节,提取信息
-- (4). 再将这些字节发给clientSock
-- 数据交互读取操作完成
-- 将从客户端收到的数据,转发给后端
local function Client2Cloud(cloudSock, clientSock)
bool done = false
repeat
local data, err1 = clientSock:receiveany(SOCKET_BUFFER_SIZE)
if err1 then
done = true
-- {
-- 如果客户端主动关闭连接,这部分能正常处理
-- socket连接管理这部分逻辑,API无论怎么调整都无法正常关闭,造成TCP连接状态异常,连接泄漏
if cloudSock.close ~= nil then
local ok, err3 = cloudSock:close()
if not ok then
cloudSock:shutdown("send")
end
else
cloudSock:shutdown("send")
end
-- }
else
local bytes, err2 = clientSock:send(data)
end
until done
end
-- 将从后端收到的数据,转发给客户端
local function Cloud2Client(clientSock, cloudSock)
bool done = false
repeat
local data, err1 = cloudSock:receiveany(SOCKET_BUFFER_SIZE)
if err1 then
done = true
-- {
-- 如果后端主动关闭逻辑,造成TCP连接状态异常,客户端程序始终检测不到连接断开, 而OpenResty的clientSock状态异常
-- socket连接管理这部分逻辑,API无论怎么调整都无法正常关闭,造成TCP连接状态异常,连接泄漏
if clientSock.close ~= nil then
local ok, err3 = clientSock:close()
if not ok then
clientSock:shutdown("send")
end
else
clientSock:shutdown("send")
end
-- }
else
local bytes, err2 = clientSock:send(data)
end
until done
end
-- 创建两个子线程,执行双向数据拷贝操作
local t1 = ngx.thread.spawn(Client2Cloud, cloudSock, clientSock)
local t2 = ngx.thread.spawn(Cloud2Client, clientSock, cloudSock)
-- 当前线程,阻塞等待子线程执行完毕
local ok, result1, result2 = ngx.thread.wait(t1, t2)
```