Sockets: close() does not close!?

Sockets: close() does not close!?

Post by Markus Stoege » Mon, 28 Jan 2002 19:41:14



Hi,

short: close() in a child process does not close the socket. Why?

long:
I have a problem with a server application that I'm writing.
I create a listening socket, wait for connections with select and once
there is an incoming connection I fork() and start exchanging data.

So far no problem. But when I try to close() the socket at the end of the
child process the socket does not really get closed.
close() returns no errors, yet the client application never notices that
the connection has been closed.
I have looked at the tcp/ip packets with tcpdump while debugging the
server/child process - when close() gets called in the child no FIN
packets are sent. I have also noticed that the FIN packets are sent only
once the _parent_ terminates.

To find out where the problem is coming from (threads or sockets) I have
removed the fork() and put the child's code directly into the parent. This
way close() works as it should.

One solution I have found is to use shutdown() instead of close() in the
child. This closes the connection right away as it should.

What I don't understand is why close()ing a socket in a child does not
work, while shutdown() does. Could someone please explain?

I'm writing this code on Linux, kernel 2.4.16 FWIW.

thanks, Max

 
 
 

Sockets: close() does not close!?

Post by David Schwart » Mon, 28 Jan 2002 20:01:02



> short: close() in a child process does not close the socket. Why?

        It depends upon what you mean by "close the socket". Close closes a
file descriptor.

Quote:> long:
> I have a problem with a server application that I'm writing.
> I create a listening socket, wait for connections with select and once
> there is an incoming connection I fork() and start exchanging data.

> So far no problem. But when I try to close() the socket at the end of the
> child process the socket does not really get closed.
> close() returns no errors, yet the client application never notices that
> the connection has been closed.

        Perhaps the socket is open elsewhere, such as in the parent. The
underlying network connection is not itself shutdown until either
'shutdown' is called or the last reference to it is closed. If you have
more than one reference, the last one must be closed for the network
connection to be closed.

Quote:> I have looked at the tcp/ip packets with tcpdump while debugging the
> server/child process - when close() gets called in the child no FIN
> packets are sent. I have also noticed that the FIN packets are sent only
> once the _parent_ terminates.

        Well then there you have it, the parent failed to close a file
descriptor referencing that network connection. The system refused to
shut down the underlying network connection because for all it knows,
the parent intends to send/receive more data.

Quote:> To find out where the problem is coming from (threads or sockets) I have
> removed the fork() and put the child's code directly into the parent. This
> way close() works as it should.

        Because in this case there's only one descriptor referencing the
socket.

Quote:> One solution I have found is to use shutdown() instead of close() in the
> child. This closes the connection right away as it should.

        Right, that's what shutdown does. However, you've probably still left a
reference to the socket in the parent, which will ultimately run the
parent out of descriptors.

Quote:> What I don't understand is why close()ing a socket in a child does not
> work, while shutdown() does. Could someone please explain?

        Until you 'close' the *last* file descriptor that references the
connection, the kernel cannot (and had better not) shut down the
underlying network connection.

        DS

 
 
 

Sockets: close() does not close!?

Post by Markus Stoege » Mon, 28 Jan 2002 20:54:55




>    Perhaps the socket is open elsewhere, such as in the parent.

That's it.. thanks for the quick answer :) I'm now closing the socket right
after fork() in the parent. So far that seems to work.

Max

 
 
 

1. shutdown(s, 2) vs close(s) for closing unix domain sockets

The specification of the shutdown(s, 2) system call is to be "more
dramatic" than the close(s) system call, since any pending data is
lost. However, if you use shutdown(s, 2) instead of close(s) under
Solaris, you will have the nasty surprise to notice that the socket
isn't released at all. This mean that the following client/server
program will block at some stage. Furtermore, if you examine the
socket name space, by netstat -f unix, you will notice that more
than one socket with name "/tmp/foo" is registered by the system...

server.c
--------

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>

main()
{
  int sock, newsock, length;
  struct sockaddr_un name;
  char* buf[1024];

  for(;;)
  {
    sock = socket(AF_UNIX, SOCK_STREAM, 0);

    name.sun_family = AF_UNIX;
    strcpy(name.sun_path, "/tmp/foo");

    bind(sock, (struct sockaddr *)&name, sizeof name);
    listen(sock, 1);
    newsock = accept(sock, (struct sockaddr *) 0, (int *) 0);
    read(newsock, buf, 1024);
    printf("%s", buf);

    shutdown(sock, 2);
    shutdown(newsock, 2);
    unlink(name.sun_path);
  }

/* gcc server.c -o server -lsocket */

client.c
--------

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define DATA "hello world\n"

main()
{
  int sock, length;
  struct sockaddr_un name;

  for(;;)
  {
    sleep(5);
    sock = socket(AF_UNIX, SOCK_STREAM, 0);

    name.sun_family = AF_UNIX;
    strcpy(name.sun_path, "/tmp/foo");

    connect(sock, (struct sockaddr *)&name, strlen(name.sun_path) +
                                          sizeof(name.sun_family));

    write(sock, DATA, sizeof(DATA));
    shutdown(sock, 2);
  }

/* gcc client.c -o client -lsocket */

Now if you simply replace all shutdown(s, 2) by close(s), it works
very well. Under SunOS-4, both calls lead to client/server program
that works. I haven't tested it with internet domain sockets yet.  

Any comment?

          \\|//
          |^ ^|          
          (O O)        
----oo0o---(_)---o0oo-------------------------------------------------------

Benoit Garbinato

Departement d'Informatique               (DI)   phone:  + 41 21 693 52 74
Ecole Polytechnique Federale de Lausanne (EPFL) fax:    + 41 21 693 39 09
CH-1015 LAUSANNE
(Switzerland)

2. '(none)'

3. Closing sockets and closing connections

4. using oracle from FreeBSD

5. socket close doesn't really close

6. sendmail problem

7. close rndc service, so port 953 will close

8. 2 Graphiccards + 2 Monitors ??

9. NFS Problem: Files aren't closed on Server (when closed on client)

10. How to avoid closing of child tasks when closing window ??

11. Mandrake & Red Hat - How close is close?

12. Closing ports by closing services

13. Netscape 4.72 on Suse 6.4: close window aborts instead of closes