Sockets: Advanced Topics 1287
The getsockopt() and setsockopt() system calls retrieve and modify options affecting
the operation of a socket.
On Linux, when a new socket is created by accept(), it does not inherit the listen-
ing sockets open file status flags, file descriptor flags, or file descriptor attributes
related to signal-driven I/O. However, it does inherit the settings of socket options.
We noted that SUSv3 is silent on these details, which vary across implementations.
Although UDP doesn’t provide the reliability guarantees of TCP, we saw that
there are nevertheless reasons why UDP can be preferable for some applications.
Finally, we outlined a few advanced features of sockets programming that we
don’t describe in detail in this book.
Further information
Refer to the sources of further information listed in Section 59.15.
61.15 Exercises
61-1. Suppose that the program in Listing 61-2 (is_echo_cl.c) was modified so that,
instead of using fork() to create two processes that operate concurrently, it instead
used just one process that first copies its standard input to the socket and then
reads the server’s response. What problem might occur when running this client?
(Look at Figure 58-8, on page 1190.)
61-2. Implement pipe() in terms of socketpair(). Use shutdown() to ensure that the resulting
pipe is unidirectional.
61-3. Implement a replacement for sendfile() using read(), write(), and lseek().
61-4. Write a program that uses getsockname() to show that, if we call listen() on a TCP
socket without first calling bind(), the socket is assigned an ephemeral port number.
61-5. Write a client and a server that permit the client to execute arbitrary shell
commands on the server host. (If you don’t implement any security mechanism in
this application, you should ensure that the server is operating under a user
account where it can do no damage if invoked by malicious users.) The client
should be executed with two command-line arguments:
$ ./is_shell_cl server-host 'some-shell-command'
After connecting to the server, the client sends the given command to the server,
and then closes its writing half of the socket using shutdown(), so that the server sees
end-of-file. The server should handle each incoming connection in a separate child
process (i.e., a concurrent design). For each incoming connection, the server
should read the command from the socket (until end-of-file), and then exec a shell
to perform the command. Here are a couple hints:
z See the implementation of system() in Section 27.7 for an example of how to
execute a shell command.
z By using dup2() to duplicate the socket on standard output and standard error,
the execed command will automatically write to the socket.