This experiment is straightforward and, at first
blush, there is not much to it. I would like to
give it a twist which, if nothing else, will test
your understanding of the stream concept. You probably
know by now that one of the differences between
UDP and TCP is that the
former deals with datagrams while the latter deals with a
stream of data. To see the implications of this first realize
that a file in some languages, COBOL for
example, is considered to be a collection of records, usually
of some fixed length and structure. Other languages, C for
example, treat a file as an unstructured stream. When you
read a file in C using, say, fread
, you must
specify the maximum number of bytes you wish to read and the function
returns the number of bytes actually read. You are imposing a
structure on the file that it does not have. In C++ this is
less obvious. If you code >> variable
, the type
of the variable determines the number of bytes and the structure
of what you are going to get. Second, to increase your
understanding and get ready for the next experiment try the
following experiment (which will take 5 minutes tops):
open two windows, in one window fire up your server using
gdb
. Set your arguments to 5193.
Set a breakpoint at line 117, and run to
that line. In the other window type client localhost
5193
. You should get the message about the number of
visits in the second window, but watch what happens in that
window when you execute the closesocket
function.
What was the client doing? Puzzle over that one. The answer
will be given in the notes on Experiment 6.2.
If you have never used gdb
, it is time to start.
Here is what you type in the first window to perform this
experiment:
gdb server
set args 5193
b 117
r
n
(when you are ready to execute the
closesocket
function)
In general you would type b main
or
something like it instead of referring to line 117.
The Optional Extension numbered 8 is vital to the
rest of the book. If you are not familiar with makefiles,
now is the time. You will find resources galore on this
topic. One problem that I have had in the past is that
explanations start at too high a level for my simple mind.
Here is an example of an extremely simple makefile:
all: client
|
client: client.c
|
*
|
gcc -o client client.c -lnsl
|
When you type make what is "made" is the first
label in the Makefile, ie, all which in this case specifies
only client. The second line specifies that client depends
upon client.c. The third line goes with the second, and
the * must be a tab. It specifies how client is to be
produced from client.c. All very simple.
Let's look ahead to Chapter 8 where we will have three executables
depending upon at least three .c files and, presumably, at least one
.h file. Take into account my situation where I am working on solutions
in Solaris and Linux (eventually Windows), and you start thinking of
ways to simplify the process. In Linux I compile with
/usr/bingcc but in
Solaris I use /opt/SUNWspro/bin/cc. I could make sure that the appropriate
compiler is in my path and just change all six occurrences of gcc with cc
or vice versa, but there is an easier way. At the top of your Makefile
put CC=/usr/bin/gcc. Then whenever you want to refer to the appropriate
compiler, type $(CC). If you do the same with LIB and $(LIB), you
only need to change two lines to turn a Solaris Makefile into a
Linux Makefile.
For Optional Extension 9 I just searched on "traceroute source code".
The first site warned that I would need to do a kernel mod, so I
tried others. I finally settled on
Traceroute-1.4a5 which gave complete directions on configuration, compilation, and installation. It worked fine.
This site is maintained by W. David Laverell
of the Computer Science Department
at Calvin College. For assistance or corrections,
please contact him at .