Subsections
My lectures are recorded as follows:
- Introduction: Lecture 1
- The client-server model:
Lecture 2
- Concurrency:
Lecture 3
- APIs:
Lecture 4,
Lecture 5
(includes the first part of a discussion on working with multiple source files)
- Client design:
Lecture 6
(mostly about makefiles and the assignment, just a bit of client design at the end),
Lecture 7
- Server design:
Lecture 8,
Lecture 9
(also includes a discussion about the second assignment),
first 48 minutes of
Lecture 10
- Multi-threaded servers:
rest of
Lecture 10,
Lecture 12,
first about 40 minutes of
Lecture 13
- Concurrency management:
rest of
Lecture 13
- Multiservice servers:
Lecture 14
- Practical aspects:
Lecture 15,
Lecture 16
- Logging and debugging:
Lecture 17
- Deadlock and starvation:
Lecture 18
- Secure programming:
Lecture 19,
Lecture 20,
first about 25 minutes of
Lecture 21
- UDP:
rest of
Lecture 21,
first about 20 minutes of
Lecture 22
- The Internet Protocol:
rest of
Lecture 22,
Lecture 23
- Socket programming on other platforms:
Lecture 24
When you use the close command to close a socket your program
tells the system that it is done with using the respective socket.
The socket is however not deallocated, and even the port
binding created by your program is still in place. Since nobody is
using it, the port binding will eventually time out (according to the
TCP timeout value, typically of the order of minutes) and die, but you
get in the meantime slapped with an “port already in use” error if
you want to bind another socket to the same port. This could become a
serious nuisance when one uses thread preallocation, and especially
when this is combined with dynamic reconfiguration.
This kind of behaviour occurs when the client does not shut down the
socket. Indeed, the TCP stack on the server side assumes that
communication will come from the client in the future unless the
client has sent an end of file. But then the end of file is sent only
upon shoudown. One solution is thus to convince one's clients to be
well-behaved, but this is no real solution from the server's
programmer point of view (typically the server's programmer has no
control over the clients).
I could find no server-side solution to convince a socket to just die
for good (should anybody know one, I would be very interested to hear
about it). So I will present here the next best thing, a workaround.
The workaround consists in convincing your socket to tell
bind to reuse the initially provided address. You can
do this by modifying the properties of the socket as follows (with
sd the descriptor of your master socket):
int reuse = 1;
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
This must be done after creating the socket and before
binding it. See the manual page of socket in Section
7 for details on this and other options, and of course the manual
page for setsockopt.
Finally, it is worth pointing out that when a client dies in an
uncivilized manner the server receives a SIGPIPE signal from
its TCP stack. This may be be used as well in the context of this
problem (though I don't really know how).
You may also be interested in this
explanation
of what happens when a socket closes.
To better understand the concepts presented during the lectures. it
may be a good idea to read the examples presented in the textbook for
a supplementary (and sometimes alternative) view of the domain, as
follows:
- Chapter 7
- deals with client design (both TCP and UDP). You
will not necessarily be able to use those clients (most ECHO ports
are actually closed), but they do make good simple examples.
- Chapters 10 and 11
- deal with TCP server design (iterative and
concurrent, respectively).
- Section 13.5
- presents an implementation that simulates
concurrency in a single thread of execution. It is similar in
spirit with the implementation you have seen in the course, but does
not allocate memory dynamically, and uses select instead of
poll. You may find it more palatable.
- Section 15.9
- presents a sample super server, worth a look.
- Chapters 7, 9, 14, and 15
- present UDP clients and servers. I
strongly advise at least a quick look at them.
Footnotes
- 1
- The code for critical regions discussed in these
slides is here.
- 2
- The code for critical regions discussed in these
slides is here.
- 3
- Exploiting buffer oferflows is explained in details
in the classic “Smashing the Stack for Fun and
Profit.”
A couple of examples are from this paper on
race conditions
- 4
- Microsoft provides a very concise
getting started
document, with just the basics (which is all you need to create socket
applications in Windows since you already know the rest of the story).
To dig further you may want to look at the following quite extensive
winsock programmer's FAQ
- 5
- More information on the matter of programming with multiple
modules can be found on the Web
here
(continued in the next section; previous section also worth a look).
See the reference material for more details on makefiles.