I have a problem with running TCP/IP server as deamon in systemd.
I have a server as shown here: https://beej.us/guide/bgnet/html/#client-server-background Every client has own process.
Server accept new client code:
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:
[Service]
Type=simple
User=root
WorkingDirectory=folder
ExecStart=binary -c config
Restart=always
The service is registered and I control it with systemctl
command.
The problem is that the number of processes in my program is gradually growing after client connected. When I run the server via command line, everything works.
Where should be the problem? Do systemd deamon need some specific configuration or client process needs to be terminated in another way?
Reap your zombies. Simplest working reaper:
int ignored;
waitpid(-1, &ignored, WNOHANG);
waitpid(-1, &ignored, WNOHANG);
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
This works because any accept only starts one new process, but we clean up two every time so the number of processes decreases every time around the loop. You will still see a few zombies but not too many. Typically only one.
More complex reapers can reduce the number of zombies to zero. sigselect
can get the job done.
I do not recommend socket activation for stuff that's used much as that pays one execve()
per connection and execve()
is not fast.