systemd
не связан с процессами, совместно использующими сокеты. systemd
запускает и контролирует всю систему, поэтому он может легко передавать дескрипторы файла сокета в течение exec()
. systemd
слушает от имени служб и всякий раз, когда будет происходить соединение, экземпляр соответствующей службы будет порожден. Here является реализация:
int main(int argc, char **argv, char **envp) {
int r, n;
int epoll_fd = -1;
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
r = install_chld_handler();
if (r < 0)
return EXIT_FAILURE;
n = open_sockets(&epoll_fd, arg_accept);
if (n < 0)
return EXIT_FAILURE;
if (n == 0) {
log_error("No sockets to listen on specified or passed in.");
return EXIT_FAILURE;
}
for (;;) {
struct epoll_event event;
r = epoll_wait(epoll_fd, &event, 1, -1);
if (r < 0) {
if (errno == EINTR)
continue;
log_error_errno(errno, "epoll_wait() failed: %m");
return EXIT_FAILURE;
}
log_info("Communication attempt on fd %i.", event.data.fd);
if (arg_accept) {
r = do_accept(argv[optind], argv + optind, envp, event.data.fd);
if (r < 0)
return EXIT_FAILURE;
} else
break;
}
...
}
После того, как соединение приходит, он будет вызывать do_accept()
:
static int do_accept(const char* name, char **argv, char **envp, int fd) {
_cleanup_free_ char *local = NULL, *peer = NULL;
_cleanup_close_ int fd_accepted = -1;
fd_accepted = accept4(fd, NULL, NULL, 0);
if (fd_accepted < 0)
return log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd);
getsockname_pretty(fd_accepted, &local);
getpeername_pretty(fd_accepted, true, &peer);
log_info("Connection from %s to %s", strna(peer), strna(local));
return fork_and_exec_process(name, argv, envp, fd_accepted);
}
наконец, itexecvpe(name, argv, envp);
вызовы и завернуть ФД в envp
. Существует трюк в нем, если fd_accepted
не равна SD_LISTEN_FDS_START
, его называют dup2()
к маркам SD_LISTEN_FDS_START
быть копией fd_accepted
:
if (start_fd != SD_LISTEN_FDS_START) {
assert(n_fds == 1);
r = dup2(start_fd, SD_LISTEN_FDS_START);
if (r < 0)
return log_error_errno(errno, "Failed to dup connection: %m");
safe_close(start_fd);
start_fd = SD_LISTEN_FDS_START;
}
Таким образом, вы можете просто использовать дескриптор файла 3, как это в вашем приложении, sd_listen_fds
будет разобрать переменные окружения LISTEN_FDS
передается от envp
:
int listen_sock;
int fd_count = sd_listen_fds(0);
if (fd_count == 1) { // assume one socket only
listen_sock = SD_LISTEN_FDS_START; // SD_LISTEN_FDS_START is a macro defined to 3
} else {
// error
}
struct sockaddr addr;
socklen_t addrlen;
while (int client_sock = accept(listen_sock, &addr, &addrlen)) {
// do something
}
Это ясно для меня, но то, что меня интересует это процесс прохождения дескриптора файла во время 'Exec()' без сотрудничества процесса выполняется. – j123b567
@ j123b567 см. Редактирование. – jfly
Благодарим вас за расширенный ответ. Я должен исследовать это немного. Для меня процессы все еще не связаны, но для меня есть два важных трюка. По умолчанию дескрипторы файлов остаются открытыми через 'execve()'. Это ново для меня. Второй трюк - это функция 'dup2()', которая делает окончательный переход fd. – j123b567