File descriptors are indeed 'inherited' when forking, but only with respect to what socket they're connected to, and closing the file descriptor will only close the socket if it's the last one associated with that socket (or file, if we're dealing with files).
What you usually do is you establish the socket, and then you fork. In the parent process (the one where fork returned non-zero) you can go ahead and close the file descriptor using close(fd)
, if you don't you'll eventually run out of file descriptors in the parent process. This is for stream (e.g. TCP) sockets, where you have one server socket listening for connections, and one socket per established connection. However, you're using UDP, so there is in fact only one socket, and if you intend to keep using it in the parent process, you'll need to figure out how to share it between parent and child process. Both can continue using it, but it'll be almost random who reads what, and in what order stuff is sent. In this case you usually have some kind of multiplexing process, which receives the packets, and forwards them to the appropriate child (per some other mechanism, such as pipes or other sockets) based on some message content (in TCP, it's the source ip/port and destination ip/port tuple).
As Matt pointed out, using shutdown
will in fact render the socket unusable (usually unwritable, but you can specify this) for all involved. In TCP, this could trigger the sending of a FIN-packet, effectively initiating the tear-down of the connection, but you're still able to receive data until the remote end acknowledges the FIN.