Я не уверен, что вы сможете сделать это так, если вы хотите сохранить s:close
только в конце всей программы. Вы можете преуспеть, переместив его до os.execute
, так как вы все равно break
(но вы, вероятно, не делаете этого в своей реальной программе). Редактировать для ясности : Реальная проблема в том, что единственное место, где вы порождаете подпроцесс в этом случае, это использование os.execute()
, и вы не можете контролировать дочернюю среду сна, в которой все наследуется от основной программы, включая дескрипторы сокетов и файлов.
Итак, канонический способ сделать это в POSIX - использовать fork(); close(s); exec();
вместо system()
(он же os.execute
), поскольку system()
/ os.execute
будет зависать в текущем состоянии процесса во время выполнения. и вы не сможете закрыть его, пока он заблокирован в подпроцессе.
Таким образом, было бы предложено захватить luaposix , использовать его функциональные возможности posix.fork()
и posix.exec()
и вызвать s:close()
в дочернем процессе fork
ed. Не должно быть так плохо, так как вы уже используете внешний пакет, полагаясь на luasocket
.
РЕДАКТИРОВАТЬ : Вот код с сильными комментариями, чтобы сделать это с luaposix:
require('socket')
require('posix')
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
local pid = posix.fork()
if pid == 0 then
print('child: running ping in background')
s:close()
-- exec() replaces current process, doesn't return.
-- execp has PATH resolution
rc = posix.execp('sleep','60s');
-- exec has no PATH resolution, probably "more secure"
--rc = posix.exec('/usr/bin/sleep','60s');
print('exec failed with rc: ' .. rc);
else
-- if you want to catch the SIGCHLD:
--print('parent: waiting for ping to return')
--posix.wait( pid )
print('parent: exiting loop')
end
break;
end
end
end
print('closing server')
s:close()
Это закрывает сокет в дочернем процессе перед вызовом exec
, и вывод netstat -nlp
показывает, что система больше не прослушивает порт 9999 при выходе из родительского процесса.
P.S. Строка print('exec failed with rc: ' .. rc);
однажды пожаловалась на проблему с типом при сбое exec. Я на самом деле не знаю Луа, так что тебе придется это исправить. :) Кроме того, fork()
может завершиться ошибкой, возвращая -1. Вероятно, следует проверить это в вашем основном коде на предмет полноты.