os.execute没有继承父级的fds

kon*_*niu 5 sockets shell lua fork exec

我有一个类似于这里描述的问题: 防止fork()复制套接字

基本上,在我的Lua脚本中,我正在生成另一个脚本:

  • 无论如何都不需要与我的脚本通信
  • 我的脚本完成后继续运行
  • 是第三方程序,我无法控制的代码

问题是我的Lua脚本打开一个TCP套接字来侦听特定端口并在它退出之后,尽管显然server:close()孩子(或更具体地说是它的孩子)保持套接字并保持端口打开(处于LISTEN状态)阻止我脚本再次运行.

这是演示问题的示例代码:

require('socket')

print('listening')
s = socket.bind("*", 9999)
s:settimeout(1)

while true do
    print('accepting connection')
    local c = s:accept()
    if c then
            c:settimeout(1)
            local rec = c:receive()
            print('received ' .. rec)
            c:close()
            if rec == "quit" then break end
            if rec == "exec" then 
                    print('running ping in background')
                    os.execute('sleep 10s &')
                    break
            end     
    end
end
print('closing server')
s:close()
Run Code Online (Sandbox Code Playgroud)

如果我运行上面的脚本并且echo quit | nc localhost 9999一切正常 - 程序退出并关闭端口.

但是,如果我执行echo exec | nc localhost 9999程序退出但是端口被生成的sleep(由确认netstat -lpn)阻止,直到它退出.

我如何以最简单的方式解决这个问题,最好不要添加任何额外的依赖项.

kon*_*niu 4

我找到了一个更简单的解决方案,它利用了在 a 中os.execute(cmd)运行的事实,事实证明,它能够关闭文件描述符,如下所示:cmdshell


例如(在 中测试ash):

    exec 3<&-                                      # closes fd3
    exec 3<&- 4<&-                                 # closes fd3 and fd4
    eval exec `seq 1 255 | sed -e 's/.*/&<\&-/'`   # closes all file descriptors 
Run Code Online (Sandbox Code Playgroud)

因此,在我的luasocket示例中,替换就足够了:

    os.execute('sleep 10s &')
Run Code Online (Sandbox Code Playgroud)

和:

    os.execute("eval exec `seq 1 255 | sed -e 's/.*/&<\\&-/'`; sleep 10s &")
Run Code Online (Sandbox Code Playgroud)

这会在执行实际命令(此处)之前关闭所有文件描述符,包括我的服务器套接字,sleep 10s以便在我的脚本退出后它不会占用端口。它还具有处理 stdoutstderr重定向的优点。

这比解决 的限制更加紧凑和简单Lua,并且不需要任何额外的依赖项。感谢#uclibc,我从嵌入式 Linux 团队那里得到了有关最终 shell 语法的出色帮助。