Reputation: 137
I got a server listening on a tcp port. When there is an incoming connection it uses accept()
and spawns a child process using fork()
. The client/child process reads some data from the connection and sends it back to the server through a pipe. After this, I would like to close the connection. I have tried to use shutdown()
and close()
from the client process without much luck.
I've checked the results of both shutdown()
and close()
and they both return 0. So apparently they run without a hitch. After both shutdown()
and close()
has been run the server receive a sigchld
from the child process. This is being handled on a general basis, but I would prefer to close down the connection before receiving the signal.
Any suggestions regarding how to do this would be much appreciated.
On a side note close()
has been used to close unneeded file descriptors and sockets throughout the server/client program, but now I'm unsure if these are actually getting closed.
Below are two code snippets.
First off is the accept()
and fork()
in the server part of the program:
if ((client_s = accept(s, &info.addr, &addrlen)) == -1) {
//Error handling
}
if ((info.pid = fork()) == -1) {
//More error handling
}
else if (info.pid == 0) {
//Closing all unneeded file descriptors
// Set default signal handler for SIGCHLD
signal(SIGCHLD, SIG_DFL);
_exit(clientStatus_main(client_s, info_pipes[1]));
}
else {
//Adding client to list of clients and closing some file descriptors.
close(client_s);
}
Finally a code snippet from the function clientStatus_main:
//Signal handling
signal(SIGINT, client_sighandler);
signal(SIGTERM, client_sighandler);
signal(SIGKILL, client_sighandler);
signal(SIGHUP, client_sighandler);
signal(SIGCHLD, SIG_DFL);
//Read data from socket
read(socket, &status_packet.type, iLength)
//Do data handling and write back to server
write(info_pipe, &status_packet, status_packet.len)
//Close down socket
res = shutdown(socket, SHUT_RDWR);
addlog(LOG_INFO, "Result of shutdown: %i\n", res); //Write to log
res = close(socket);
addlog(LOG_INFO, "Result of close: %i\n", res);
return (iCount > 0 ? 0 : -1);
Any good ideas?
*EDIT: After reading the comments I've tried to do close(client_s)
from the parent process, but it didn't solve my problem. For clarity, I've also added the line to the code snippet.
Upvotes: 2
Views: 473
Reputation: 137
This is kind of embarrassing, but it seems that the problem wasn't with close()
or shutdown()
after all. The comments and the answer by Klas Lindbäck got me thinking and I experimented a bit and found that the SIGCHLD
was sent because the client actually closed down the connection at the same time the child process did.
So my solution has been inspired by the suggestion by Klas Lindbäck. The child process sends the process ID through the pipe mentioned earlier and the parent process can now safely ignore/block the SIGCHLD
sent from this process.
Upvotes: 0
Reputation: 33273
There are three processes involved:
The client: connect to the listening socket of the parent.
The parent: server process that listens on a socket, accepts connections and hands them over to a child.
The child: server process that talks to the client over the established connection.
The established connection exists only between the child
and the client
. The parent
has no way of detecting when the client socket is closed down from either side.
There are two ways to inform the parent
that the child
is closing the connection and terminating, either catch the SIGCHLD
signal or let the child
send a message to the parent
, for instance over the pipe
mentioned in the question.
Upvotes: 1