在systemd之类的不相关进程之间共享套接字

时间:2017-01-29 10:41:06

标签: linux sockets share file-descriptor systemd

有多个问题和答案如何做,但两个过程必须合作

systemd中,有一个功能socket activation,您只需在流程中打开并准备好文件描述符,无需任何合作。您可以使用文件描述符3SD_LISTEN_FDS_START),它已经被systemd激活了socket。

systemd如何做到这一点?我无法找到任何相关的源代码。

修改

我知道,如何编写systemd socket激活服务,但我对从systemd角度传递文件描述符到我的服务的过程感兴趣。

E.g。如果我想编写自己的套接字激活器,那就像systemd一样。

1 个答案:

答案 0 :(得分:2)

INSERT INTO tbl_name (a,b,c) VALUES(v1,v2,v3),(v4,v5,v6),(v7,v8,v9); 与共享套接字的进程不无关systemd启动并监督整个系统,因此它可以轻松地在systemd期间传递套接字文件描述符。 exec()代表服务进行侦听,无论何时进入连接,都会产生相应服务的实例。 Here是实施:

systemd

连接进来后,会调用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()

最后,it调用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); } 并将fd包装在execvpe(name, argv, envp);中。其中有一个技巧,如果envp不等于fd_accepted,则调用dup2()使SD_LISTEN_FDS_START成为SD_LISTEN_FDS_START的副本:

fd_accepted

所以你可以在你的应用程序中使用这样的文件描述符3, 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; } 将解析从sd_listen_fds传递的环境变量LISTEN_FDS

envp