【发布时间】:2021-03-18 17:23:47
【问题描述】:
我在 systemd 中将 TCP/IP 服务器作为守护进程运行时遇到问题。
我有一个服务器,如下所示:https://beej.us/guide/bgnet/html/#client-server-background 每个客户都有自己的流程。
服务器接受新的客户端代码:
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
// some logic here
// When the client receives a specific message, it ends. Of course I call close socket and exit with exit code 0.
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
服务:
[Service]
Type=simple
User=root
WorkingDirectory=folder
ExecStart=binary -c config
Restart=always
服务已注册,我使用systemctl 命令控制它。
问题是我的程序中的进程数在客户端连接后逐渐增加。 当我通过命令行运行服务器时,一切正常。
问题应该出在哪里? systemd 守护进程是否需要某些特定配置或客户端进程需要以其他方式终止?
【问题讨论】:
-
完成后终止是您的应用程序的责任。当您的应用程序完成它应该做的任何事情时,systemd 什么都不知道,也不可能有任何想法。无论出于何种原因,从 systemd 启动时,您的应用程序进程都不会终止。您必须弄清楚原因,只有您拥有对源代码的完全访问权限,并且可以对其进行调试。
-
@SamVarshavchik 应用程序永远不应该退出。它必须监听以接受连接。问题是从命令行与 systemd 守护程序运行的。从命令行它正在工作。如果服务配置正确或需要对我的代码实施 systemd 守护程序的特定行为,我需要建议。
-
好吧,有些东西正在启动您的应用程序。显示的系统服务是相当基本的,除非您在 systemd 中发现某种错误,否则您必须在您的应用中查找问题。
-
吹毛求疵:你没有多线程服务器。您有一个多进程服务器。如今,不分叉而是创建线程更容易(而且通常更有效)。无论如何,只需附加到应该已死但未使用
gdb的进程并检查活动调用堆栈。还有简单的ps命令可以告诉进程的状态,也蛮有用的。 -
accept可能不是最好的系统设计。您给出的示例是您 1980 年的基本设计,但 systemd 有一些称为“套接字激活”的东西。有关详细信息,请参阅0pointer.de/blog/projects/socket-activation.html。每个客户端仍然有一个进程,但 systemd 会为您设置套接字。