Correct errors reported by textproc/igor:

- wrap long lines
- add two spaces after a sentence stop
- use tabs instead of spaces
- bad tag indent
This commit is contained in:
Benedict Reuschling 2018-08-26 18:34:50 +00:00
parent 93632dc9d5
commit d5508ba579
Notes: svn2git 2020-12-08 03:00:23 +00:00
svn path=/head/; revision=52177

View file

@ -4,29 +4,37 @@
$FreeBSD$
-->
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:id="sockets">
<info><title>Sockets</title>
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="sockets">
<info>
<title>Sockets</title>
<authorgroup>
<author><personname><firstname>G. Adam</firstname><surname>Stanislav</surname></personname><contrib>Contributed by </contrib></author>
<author>
<personname>
<firstname>G. Adam</firstname>
<surname>Stanislav</surname>
</personname>
<contrib>Contributed by </contrib>
</author>
</authorgroup>
</info>
<sect1 xml:id="sockets-synopsis">
<title>Synopsis</title>
<para><acronym>BSD</acronym> sockets take interprocess
communications to a new level. It is no longer necessary for the
communicating processes to run on the same machine. They still
<emphasis>can</emphasis>, but they do not have to.</para>
communications to a new level. It is no longer necessary for
the communicating processes to run on the same machine. They
still <emphasis>can</emphasis>, but they do not have to.</para>
<para>Not only do these processes not have to run on the same
machine, they do not have to run under the same operating
system. Thanks to <acronym>BSD</acronym> sockets, your FreeBSD
software can smoothly cooperate with a program running on a
&macintosh;, another one running on a &sun; workstation, yet another
one running under &windows; 2000, all connected with an
&macintosh;, another one running on a &sun; workstation, yet
another one running under &windows; 2000, all connected with an
Ethernet-based local area network.</para>
<para>But your software can equally well cooperate with processes
@ -45,9 +53,9 @@
<para>We have already hinted on the <emphasis>diversity</emphasis>
of networking. Many different systems have to talk to each
other. And they have to speak the same language. They also have
to <emphasis>understand</emphasis> the same language the same
way.</para>
other. And they have to speak the same language. They also
have to <emphasis>understand</emphasis> the same language the
same way.</para>
<para>People often think that <emphasis>body language</emphasis>
is universal. But it is not. Back in my early teens, my father
@ -67,17 +75,17 @@
his almonds, and walked away. To an uninformed observer, I did
not change the body language: I continued using the language of
shaking and nodding my head. What changed was the
<emphasis>meaning</emphasis> of the body language. At first, the
vendor and I interpreted the same language as having completely
different meaning. I had to adjust my own interpretation of that
language so the vendor would understand.</para>
<emphasis>meaning</emphasis> of the body language. At first,
the vendor and I interpreted the same language as having
completely different meaning. I had to adjust my own
interpretation of that language so the vendor would
understand.</para>
<para>It is the same with computers: The same symbols may have
different, even outright opposite meaning. Therefore, for
two computers to understand each other, they must not only
agree on the same <emphasis>language</emphasis>, but on the
same <emphasis>interpretation</emphasis> of the language.
</para>
different, even outright opposite meaning. Therefore, for two
computers to understand each other, they must not only agree on
the same <emphasis>language</emphasis>, but on the same
<emphasis>interpretation</emphasis> of the language.</para>
</sect1>
<sect1 xml:id="sockets-protocols">
@ -182,12 +190,12 @@
<acronym>HTTP</acronym>. This protocol can tell us exactly that
the data represents an image, and that it uses the
<acronym>PNG</acronym> protocol. It can also tell us some other
things, but let us stay focused on protocol layers here.
</para>
things, but let us stay focused on protocol layers here.</para>
<para>So, now we have some data wrapped in the <acronym>PNG</acronym>
protocol, wrapped in the <acronym>HTTP</acronym> protocol.
How did we get it from the server?</para>
<para>So, now we have some data wrapped in the
<acronym>PNG</acronym> protocol, wrapped in the
<acronym>HTTP</acronym> protocol. How did we get it from the
server?</para>
<para>By using <acronym>TCP/IP</acronym> over Ethernet, that is
how. Indeed, that is three more protocols. Instead of
@ -197,11 +205,11 @@
<para>Ethernet is an interesting system of connecting computers in
a <emphasis>local area network</emphasis>
(<acronym>LAN</acronym>). Each computer has a <emphasis>network
interface card</emphasis> (<acronym>NIC</acronym>), which has a
unique 48-bit <acronym>ID</acronym> called its
interface card</emphasis> (<acronym>NIC</acronym>), which has
a unique 48-bit <acronym>ID</acronym> called its
<emphasis>address</emphasis>. No two Ethernet
<acronym>NIC</acronym>s in the world have the same address.
</para>
<acronym>NIC</acronym>s in the world have the same
address.</para>
<para>These <acronym>NIC</acronym>s are all connected with each
other. Whenever one computer wants to communicate with another
@ -209,22 +217,22 @@
over the network. Every <acronym>NIC</acronym> sees the
message. But as part of the Ethernet
<emphasis>protocol</emphasis>, the data contains the address of
the destination <acronym>NIC</acronym> (among other things). So,
only one of all the network interface cards will pay attention
to it, the rest will ignore it.</para>
the destination <acronym>NIC</acronym> (among other things).
So, only one of all the network interface cards will pay
attention to it, the rest will ignore it.</para>
<para>But not all computers are connected to the same
network. Just because we have received the data over our
Ethernet does not mean it originated in our own local area
network. It could have come to us from some other network (which
may not even be Ethernet based) connected with our own network
via the Internet.</para>
<para>But not all computers are connected to the same network.
Just because we have received the data over our Ethernet does
not mean it originated in our own local area network. It could
have come to us from some other network (which may not even be
Ethernet based) connected with our own network via the
Internet.</para>
<para>All data is transferred over the Internet using
<acronym>IP</acronym>, which stands for <emphasis>Internet
Protocol</emphasis>. Its basic role is to let us know where in
the world the data has arrived from, and where it is supposed to
go to. It does not <emphasis>guarantee</emphasis> we will
Protocol</emphasis>. Its basic role is to let us know where
in the world the data has arrived from, and where it is supposed
to go to. It does not <emphasis>guarantee</emphasis> we will
receive the data, only that we will know where it came from
<emphasis>if</emphasis> we do receive it.</para>
@ -260,10 +268,10 @@
<para>Luckily for you, you are <emphasis>not</emphasis> supposed
to handle it all. You <emphasis>are</emphasis> supposed to
handle some of it, but not all of it. Specifically, you need not
worry about the physical connection (in our case Ethernet and
possibly <acronym>PPP</acronym>, etc). Nor do you need to handle
the Internet Protocol, or the Transmission Control
handle some of it, but not all of it. Specifically, you need
not worry about the physical connection (in our case Ethernet
and possibly <acronym>PPP</acronym>, etc). Nor do you need to
handle the Internet Protocol, or the Transmission Control
Protocol.</para>
<para>In other words, you do not have to do anything to receive
@ -327,8 +335,7 @@
example, then, sockets would let us receive an <emphasis>HTTP
file</emphasis>, so to speak. It would then be up to us to
extract the <emphasis><acronym>PNG</acronym> file</emphasis>
from it.
</para>
from it.</para>
<para>Because of the complexity of internetworking, we cannot just
use the <function role="syscall">open</function> system call, or
@ -368,9 +375,7 @@
<para>The one function used by both, clients and servers, is
&man.socket.2;. It is declared this way:</para>
<programlisting>
int socket(int domain, int type, int protocol);
</programlisting>
<programlisting>int socket(int domain, int type, int protocol);</programlisting>
<para>The return value is of the same type as that of
<function>open</function>, an integer. FreeBSD allocates
@ -439,8 +444,7 @@ int socket(int domain, int type, int protocol);
<varname>struct sockaddr</varname>. This structure is
declared in the same file:</para>
<programlisting>
/*
<programlisting>/*
* Structure used by kernel to store most
* addresses.
*/
@ -449,8 +453,7 @@ struct sockaddr {
sa_family_t sa_family; /* address family */
char sa_data[14]; /* actually longer; address value */
};
#define SOCK_MAXADDRLEN 255 /* longest possible addresses */
</programlisting>
#define SOCK_MAXADDRLEN 255 /* longest possible addresses */</programlisting>
<para>Please note the <emphasis>vagueness</emphasis> with
which the <varname>sa_data</varname> field is declared,
@ -473,8 +476,7 @@ struct sockaddr {
right before the definition of
<varname>sockaddr</varname>:</para>
<programlisting>
/*
<programlisting>/*
* Address families.
*/
#define AF_UNSPEC 0 /* unspecified */
@ -519,9 +521,7 @@ struct sockaddr {
#define AF_SCLUSTER 34 /* Sitara cluster protocol */
#define AF_ARP 35
#define AF_BLUETOOTH 36 /* Bluetooth sockets */
#define AF_MAX 37
</programlisting>
#define AF_MAX 37</programlisting>
<para>The one used for <acronym>IP</acronym> is
<symbol>AF_INET</symbol>. It is a symbol for the constant
@ -534,13 +534,12 @@ struct sockaddr {
used.</para>
<para>Specifically, whenever the <emphasis>address
family</emphasis> is <symbol>AF_INET</symbol>, we can use
<varname>struct sockaddr_in</varname> found in
family</emphasis> is <symbol>AF_INET</symbol>, we can
use <varname>struct sockaddr_in</varname> found in
<filename>netinet/in.h</filename>, wherever
<varname>sockaddr</varname> is expected:</para>
<programlisting>
/*
<programlisting>/*
* Socket address, internet style.
*/
struct sockaddr_in {
@ -549,8 +548,7 @@ struct sockaddr_in {
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
</programlisting>
};</programlisting>
<para>We can visualize its organization this way:</para>
@ -590,11 +588,13 @@ struct sockaddr_in {
that its server will write a text string representing the
current date and time to port 13. We want to use
<acronym>TCP/IP</acronym>, so we need to specify
<constant>AF_INET</constant> in the address family
field. <constant>AF_INET</constant> is defined as
<constant>AF_INET</constant> in the address family field.
<constant>AF_INET</constant> is defined as
<constant>2</constant>. Let us use the
<acronym>IP</acronym> address of <systemitem class="ipaddress">192.43.244.18</systemitem>, which is the time
server of US federal government (<systemitem class="fqdomainname">time.nist.gov</systemitem>).</para>
<acronym>IP</acronym> address of <systemitem
class="ipaddress">192.43.244.18</systemitem>, which is
the time server of US federal government (<systemitem
class="fqdomainname">time.nist.gov</systemitem>).</para>
<mediaobject>
<imageobject>
@ -624,28 +624,27 @@ struct sockaddr_in {
type, which is defined in
<filename>netinet/in.h</filename>:</para>
<programlisting>
/*
<programlisting>/*
* Internet address (a structure for historical reasons)
*/
struct in_addr {
in_addr_t s_addr;
};
</programlisting>
};</programlisting>
<para>In addition, <varname>in_addr_t</varname> is a 32-bit
integer.</para>
<para>The <systemitem class="ipaddress">192.43.244.18</systemitem> is
just a convenient notation of expressing a 32-bit integer
by listing all of its 8-bit bytes, starting with the
<para>The <systemitem
class="ipaddress">192.43.244.18</systemitem> is just a
convenient notation of expressing a 32-bit integer by
listing all of its 8-bit bytes, starting with the
<emphasis>most significant</emphasis> one.</para>
<para>So far, we have viewed <varname>sockaddr</varname> as
an abstraction. Our computer does not store
<varname>short</varname> integers as a single 16-bit
entity, but as a sequence of 2 bytes. Similarly, it stores
32-bit integers as a sequence of 4 bytes.</para>
entity, but as a sequence of 2 bytes. Similarly, it
stores 32-bit integers as a sequence of 4 bytes.</para>
<para>Suppose we coded something like this:</para>
@ -655,8 +654,8 @@ sa.sin_addr.s_addr = (((((192 &lt;&lt; 8) | 43) &lt;&lt; 8) | 244) &lt;&lt; 8) |
<para>What would the result look like?</para>
<para>Well, that depends, of course. On a &pentium;, or other
x86, based computer, it would look like this:</para>
<para>Well, that depends, of course. On a &pentium;, or
other x86, based computer, it would look like this:</para>
<mediaobject>
<imageobject>
@ -681,8 +680,7 @@ sa.sin_addr.s_addr = (((((192 &lt;&lt; 8) | 43) &lt;&lt; 8) | 244) &lt;&lt; 8) |
</textobject>
</mediaobject>
<para>On a different system, it might look like this:
</para>
<para>On a different system, it might look like this:</para>
<mediaobject>
<imageobject>
@ -711,10 +709,10 @@ sa.sin_addr.s_addr = (((((192 &lt;&lt; 8) | 43) &lt;&lt; 8) | 244) &lt;&lt; 8) |
above two are the most common ways in use today.</para>
<para>Ordinarily, wanting to write portable code,
programmers pretend that these differences do not
exist. And they get away with it (except when they code in
assembly language). Alas, you cannot get away with it that
easily when coding for sockets.</para>
programmers pretend that these differences do not exist.
And they get away with it (except when they code in
assembly language). Alas, you cannot get away with it
that easily when coding for sockets.</para>
<para>Why?</para>
@ -725,7 +723,8 @@ sa.sin_addr.s_addr = (((((192 &lt;&lt; 8) | 43) &lt;&lt; 8) | 244) &lt;&lt; 8) |
(<acronym>LSB</acronym>) first.</para>
<para>You might be wondering, <emphasis><quote>So, will
sockets not handle it for me?</quote></emphasis></para>
sockets not handle it for
me?</quote></emphasis></para>
<para>It will not.</para>
@ -741,21 +740,21 @@ sa.sin_addr.s_addr = (((((192 &lt;&lt; 8) | 43) &lt;&lt; 8) | 244) &lt;&lt; 8) |
whatever order is native to the computer).</para>
<para>But the rest of the data is just
<varname>sa_data[14]</varname> as far as sockets
goes. Depending on the <emphasis>address
family</emphasis>, sockets just forwards that data to its
destination.</para>
<varname>sa_data[14]</varname> as far as sockets goes.
Depending on the <emphasis>address family</emphasis>,
sockets just forwards that data to its destination.</para>
<para>Indeed, when we enter a port number, it is because we
want the other computer to know what service we are asking
for. And, when we are the server, we read the port number
so we know what service the other computer is expecting
from us. Either way, sockets only has to forward the port
number as data. It does not interpret it in any way.</para>
number as data. It does not interpret it in any
way.</para>
<para>Similarly, we enter the <acronym>IP</acronym> address
to tell everyone on the way where to send our data
to. Sockets, again, only forwards it as data.</para>
to tell everyone on the way where to send our data to.
Sockets, again, only forwards it as data.</para>
<para>That is why, we (the <emphasis>programmers</emphasis>,
not the <emphasis>sockets</emphasis>) have to distinguish
@ -833,17 +832,17 @@ sa.sin_addr.s_addr = (((((192 &lt;&lt; 8) | 43) &lt;&lt; 8) | 244) &lt;&lt; 8) |
order</emphasis>.</para>
<para>We have several ways of dealing with it. One would be
to <emphasis>reverse</emphasis> the values in our code:
</para>
to <emphasis>reverse</emphasis> the values in our
code:</para>
<programlisting>sa.sin_family = AF_INET;
sa.sin_port = 13 &lt;&lt; 8;
sa.sin_addr.s_addr = (((((18 &lt;&lt; 8) | 244) &lt;&lt; 8) | 43) &lt;&lt; 8) | 192;</programlisting>
<para>This will <emphasis>trick</emphasis> our compiler
into storing the data in the <emphasis>network byte
order</emphasis>. In some cases, this is exactly the way
to do it (e.g., when programming in assembly
<para>This will <emphasis>trick</emphasis> our compiler into
storing the data in the <emphasis>network byte
order</emphasis>. In some cases, this is exactly the
way to do it (e.g., when programming in assembly
language). In most cases, however, it can cause a
problem.</para>
@ -862,10 +861,10 @@ sa.sin_addr.s_addr = (((((18 &lt;&lt; 8) | 244) &lt;&lt; 8) | 43) &lt;&lt; 8) |
<para>You have since forgotten that you had forced all of
your constants to the opposite of the <emphasis>host
order</emphasis>. You spend some quality time tearing out
your hair, calling the names of all gods you ever heard
of (and some you made up), hitting your monitor with a
nerf bat, and performing all the other traditional
order</emphasis>. You spend some quality time tearing
out your hair, calling the names of all gods you ever
heard of (and some you made up), hitting your monitor with
a nerf bat, and performing all the other traditional
ceremonies of trying to figure out why something that has
worked so well is suddenly not working at all.</para>
@ -876,10 +875,10 @@ sa.sin_addr.s_addr = (((((18 &lt;&lt; 8) | 244) &lt;&lt; 8) | 43) &lt;&lt; 8) |
problem. Someone else has created the &man.htons.3; and
&man.htonl.3; C functions to convert a
<varname>short</varname> and <varname>long</varname>
respectively from the <emphasis>host byte
order</emphasis> to the <emphasis>network byte
order</emphasis>, and the &man.ntohs.3; and &man.ntohl.3;
C functions to go the other way.</para>
respectively from the <emphasis>host byte order</emphasis>
to the <emphasis>network byte order</emphasis>, and the
&man.ntohs.3; and &man.ntohl.3; C functions to go the
other way.</para>
<para>On <emphasis><acronym>MSB</acronym>-first</emphasis>
systems these functions do nothing. On
@ -887,11 +886,9 @@ sa.sin_addr.s_addr = (((((18 &lt;&lt; 8) | 244) &lt;&lt; 8) | 43) &lt;&lt; 8) |
they convert values to the proper order.</para>
<para>So, regardless of what system your software is
compiled on, your data will end up in the correct order
if you use these functions.</para>
compiled on, your data will end up in the correct order if
you use these functions.</para>
</sect4>
</sect3>
<sect3 xml:id="sockets-client-functions">
@ -913,9 +910,7 @@ sa.sin_addr.s_addr = (((((18 &lt;&lt; 8) | 244) &lt;&lt; 8) | 43) &lt;&lt; 8) |
connect it to a specific port on a remote system. It uses
&man.connect.2;:</para>
<programlisting>
int connect(int s, const struct sockaddr *name, socklen_t namelen);
</programlisting>
<programlisting>int connect(int s, const struct sockaddr *name, socklen_t namelen);</programlisting>
<para>The <varname>s</varname> argument is the socket, i.e.,
the value returned by the <function>socket</function>
@ -938,18 +933,17 @@ int connect(int s, const struct sockaddr *name, socklen_t namelen);
listening at the specified port. Or it may outright
<emphasis>refuse</emphasis> any request for specific
code.</para>
</sect4>
<sect4 xml:id="sockets-first-client">
<title>Our First Client</title>
<para>We now know enough to write a very simple client, one
that will get current time from <systemitem class="ipaddress">192.43.244.18</systemitem> and print it to
<filename>stdout</filename>.</para>
that will get current time from <systemitem
class="ipaddress">192.43.244.18</systemitem> and print
it to <filename>stdout</filename>.</para>
<programlisting>
/*
<programlisting>/*
* daytime.c
*
* Programmed by G. Adam Stanislav
@ -987,8 +981,7 @@ int main() {
close(s);
return 0;
}
</programlisting>
}</programlisting>
<para>Go ahead, enter it in your editor, save it as
<filename>daytime.c</filename>, then compile and run
@ -1003,21 +996,19 @@ int main() {
<para>In this case, the date was June 19, 2001, the time was
02:29:25 <acronym>UTC</acronym>. Naturally, your results
will vary.</para>
</sect4>
</sect3>
<sect3 xml:id="sockets-server-functions">
<title>Server Functions</title>
<para>The typical server does not initiate the
connection. Instead, it waits for a client to call it and
request services. It does not know when the client will
call, nor how many clients will call. It may be just sitting
there, waiting patiently, one moment, The next moment, it
can find itself swamped with requests from a number of
clients, all calling in at the same time.</para>
<para>The typical server does not initiate the connection.
Instead, it waits for a client to call it and request
services. It does not know when the client will call, nor
how many clients will call. It may be just sitting there,
waiting patiently, one moment, The next moment, it can find
itself swamped with requests from a number of clients, all
calling in at the same time.</para>
<para>The sockets interface offers three basic functions to
handle this.</para>
@ -1036,22 +1027,18 @@ int main() {
specific extension. We use &man.bind.2; to tell sockets
which port we want to serve.</para>
<programlisting>
int bind(int s, const struct sockaddr *addr, socklen_t addrlen);
</programlisting>
<programlisting>int bind(int s, const struct sockaddr *addr, socklen_t addrlen);</programlisting>
<para>Beside specifying the port in <varname>addr</varname>,
the server may include its <acronym>IP</acronym>
address. However, it can just use the symbolic constant
the server may include its <acronym>IP</acronym> address.
However, it can just use the symbolic constant
<symbol>INADDR_ANY</symbol> to indicate it will serve all
requests to the specified port regardless of what its
<acronym>IP</acronym> address is. This symbol, along with
several similar ones, is declared in
<filename>netinet/in.h</filename></para>
<programlisting>
#define INADDR_ANY (u_int32_t)0x00000000
</programlisting>
<programlisting>#define INADDR_ANY (u_int32_t)0x00000000</programlisting>
<para>Suppose we were writing a server for the
<emphasis>daytime</emphasis> protocol over
@ -1089,23 +1076,21 @@ int bind(int s, const struct sockaddr *addr, socklen_t addrlen);
<para>To continue our office phone analogy, after you have
told the phone central operator what extension you will be
at, you now walk into your office, and make sure your own
phone is plugged in and the ringer is turned on. Plus, you
make sure your call waiting is activated, so you can hear
the phone ring even while you are talking to someone.</para>
phone is plugged in and the ringer is turned on. Plus,
you make sure your call waiting is activated, so you can
hear the phone ring even while you are talking to
someone.</para>
<para>The server ensures all of that with the &man.listen.2;
function.</para>
<programlisting>
int listen(int s, int backlog);
</programlisting>
<programlisting>int listen(int s, int backlog);</programlisting>
<para>In here, the <varname>backlog</varname> variable tells
sockets how many incoming requests to accept while you are
busy processing the last request. In other words, it
determines the maximum size of the queue of pending
connections.</para>
</sect4>
<sect4 xml:id="sockets-accept">
@ -1119,9 +1104,7 @@ int listen(int s, int backlog);
<para>The server accepts the connection by using the
&man.accept.2; function.</para>
<programlisting>
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
</programlisting>
<programlisting>int accept(int s, struct sockaddr *addr, socklen_t *addrlen);</programlisting>
<para>Note that this time <varname>addrlen</varname> is a
pointer. This is necessary because in this case it is the
@ -1138,11 +1121,10 @@ int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
variable we passed to <function>listen</function>?) until
we <function>close</function> it.</para>
<para>Now, the new socket is meant only for
communications. It is fully connected. We cannot pass it
to <function>listen</function> again, trying to accept
<para>Now, the new socket is meant only for communications.
It is fully connected. We cannot pass it to
<function>listen</function> again, trying to accept
additional connections.</para>
</sect4>
<sect4 xml:id="sockets-first-server">
@ -1163,8 +1145,7 @@ int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
starts an endless loop, which accepts a connection, serves
it, and eventually closes its socket.</para>
<programlisting>
/*
<programlisting>/*
* daytimed - a port 13 server
*
* Programmed by G. Adam Stanislav
@ -1251,18 +1232,15 @@ int main() {
fclose(client);
}
}
</programlisting>
}</programlisting>
<para>We start by creating a socket. Then we fill out the
<varname>sockaddr_in</varname> structure in
<varname>sa</varname>. Note the conditional use of
<symbol>INADDR_ANY</symbol>:</para>
<programlisting>
if (INADDR_ANY)
sa.sin_addr.s_addr = htonl(INADDR_ANY);
</programlisting>
<programlisting>if (INADDR_ANY)
sa.sin_addr.s_addr = htonl(INADDR_ANY);</programlisting>
<para>Its value is <constant>0</constant>. Since we have
just used <function>bzero</function> on the entire
@ -1291,32 +1269,39 @@ int main() {
its backlog to <constant>4</constant>. It does not need a
large value here because <emphasis>daytime</emphasis> is
not a protocol many clients request all the time, and
because it can process each request instantly anyway.</para>
because it can process each request instantly
anyway.</para>
<para>Finally, the daemon starts an endless loop, which
performs the following steps:</para>
<procedure>
<step><para> Call <function>accept</function>. It waits
here until a client contacts it. At that point, it
<step>
<para>Call <function>accept</function>. It waits here
until a client contacts it. At that point, it
receives a new socket, <varname>c</varname>, which it
can use to communicate with this particular client.
</para></step>
can use to communicate with this particular
client.</para>
</step>
<step><para>It uses the C function
<function>fdopen</function> to turn the socket from a
low-level <emphasis>file descriptor</emphasis> to a
C-style <varname>FILE</varname> pointer. This will allow
the use of <function>fprintf</function> later on.
</para></step>
<step><para>It checks the time, and prints it in the
<emphasis><acronym>ISO</acronym> 8601</emphasis> format
to the <varname>client</varname> <quote>file</quote>. It
then uses <function>fclose</function> to close the
file. That will automatically close the socket as well.
</para></step>
<step>
<para>It uses the C function <function>fdopen</function>
to turn the socket from a low-level <emphasis>file
descriptor</emphasis> to a C-style
<varname>FILE</varname> pointer. This will allow the
use of <function>fprintf</function> later
on.</para>
</step>
<step>
<para>It checks the time, and prints it in the
<emphasis><acronym>ISO</acronym> 8601</emphasis>
format to the <varname>client</varname>
<quote>file</quote>. It then uses
<function>fclose</function> to close the file. That
will automatically close the socket as
well.</para>
</step>
</procedure>
<para>We can <emphasis>generalize</emphasis> this, and use
@ -1364,12 +1349,13 @@ int main() {
<para>This flowchart is good for <emphasis>sequential
servers</emphasis>, i.e., servers that can serve one
client at a time, just as we were able to with our
<emphasis>daytime</emphasis> server. This is only possible
whenever there is no real <quote>conversation</quote>
going on between the client and the server: As soon as the
server detects a connection to the client, it sends out
some data and closes the connection. The entire operation
may take nanoseconds, and it is finished.</para>
<emphasis>daytime</emphasis> server. This is only
possible whenever there is no real
<quote>conversation</quote> going on between the client
and the server: As soon as the server detects a connection
to the client, it sends out some data and closes the
connection. The entire operation may take nanoseconds,
and it is finished.</para>
<para>The advantage of this flowchart is that, except for
the brief moment after the parent
@ -1395,8 +1381,8 @@ int main() {
<para>Not all protocols are that simple. Many receive a
request from the client, reply to it, then receive another
request from the same client. Because of that, they do not
know in advance how long they will be serving the
request from the same client. Because of that, they do
not know in advance how long they will be serving the
client. Such servers usually start a new process for each
client. While the new process is serving its client, the
daemon can continue listening for more connections.</para>
@ -1430,9 +1416,9 @@ bind: Permission denied
bind: Address already in use
&prompt.root;</screen>
<para>Every port can only be bound by one program at a
time. Our first attempt was indeed successful: It started
the child daemon and returned quietly. It is still running
<para>Every port can only be bound by one program at a time.
Our first attempt was indeed successful: It started the
child daemon and returned quietly. It is still running
and will continue to run until you either kill it, or any
of its system calls fail, or you reboot the system.</para>
@ -1458,8 +1444,8 @@ Connection closed by foreign host.
<para>If you have access to another &unix; system via
<application>telnet</application>, you can use it to test
accessing the server remotely. My computer does not have a
static <acronym>IP</acronym> address, so this is what I
accessing the server remotely. My computer does not have
a static <acronym>IP</acronym> address, so this is what I
did:</para>
<screen>&prompt.user; <userinput>who</userinput>
@ -1475,8 +1461,8 @@ Escape character is '^]'.
Connection closed by foreign host.
&prompt.user;</screen>
<para>Again, it worked. Will it work using the domain name?
</para>
<para>Again, it worked. Will it work using the domain
name?</para>
<screen>&prompt.user; <userinput>telnet r47.bfm.org 13</userinput>
@ -1489,17 +1475,13 @@ Connection closed by foreign host.
<para>By the way, <application>telnet</application> prints
the <emphasis>Connection closed by foreign host</emphasis>
message after our daemon has closed the socket. This shows
us that, indeed, using
message after our daemon has closed the socket. This
shows us that, indeed, using
<function>fclose(client);</function> in our code works as
advertised.</para>
</sect4>
</sect3>
</sect2>
</sect1>
<sect1 xml:id="sockets-helper-functions">
@ -1511,21 +1493,18 @@ Connection closed by foreign host.
<acronym>IP</acronym> address. But we do not always know the
<acronym>IP</acronym> address. Even if we do, our software is
more flexible if it allows the user to enter the
<acronym>IP</acronym> address, or even the domain name.
</para>
<acronym>IP</acronym> address, or even the domain name.</para>
<sect2 xml:id="sockets-gethostbyname">
<title><function>gethostbyname</function></title>
<para>While there is no way to pass the domain name directly to
any of the sockets functions, the FreeBSD C library comes with
the &man.gethostbyname.3; and &man.gethostbyname2.3; functions,
declared in <filename>netdb.h</filename>.</para>
the &man.gethostbyname.3; and &man.gethostbyname2.3;
functions, declared in <filename>netdb.h</filename>.</para>
<programlisting>
struct hostent * gethostbyname(const char *name);
struct hostent * gethostbyname2(const char *name, int af);
</programlisting>
<programlisting>struct hostent * gethostbyname(const char *name);
struct hostent * gethostbyname2(const char *name, int af);</programlisting>
<para>Both return a pointer to the <varname>hostent</varname>
structure, with much information about the domain. For our
@ -1538,8 +1517,7 @@ struct hostent * gethostbyname2(const char *name, int af);
much more useful&mdash;version of our
<application>daytime</application> program:</para>
<programlisting>
/*
<programlisting>/*
* daytime.c
*
* Programmed by G. Adam Stanislav
@ -1589,24 +1567,26 @@ int main(int argc, char *argv[]) {
close(s);
return 0;
}
</programlisting>
}</programlisting>
<para>We now can type a domain name (or an <acronym>IP</acronym>
address, it works both ways) on the command line, and the
program will try to connect to its
<emphasis>daytime</emphasis> server. Otherwise, it will still
default to <systemitem class="fqdomainname">time.nist.gov</systemitem>. However, even in
this case we will use <function>gethostbyname</function>
rather than hard coding <systemitem class="ipaddress">192.43.244.18</systemitem>. That way, even if its
<acronym>IP</acronym> address changes in the future, we will
still find it.</para>
default to <systemitem
class="fqdomainname">time.nist.gov</systemitem>. However,
even in this case we will use
<function>gethostbyname</function> rather than hard coding
<systemitem class="ipaddress">192.43.244.18</systemitem>.
That way, even if its <acronym>IP</acronym> address changes in
the future, we will still find it.</para>
<para>Since it takes virtually no time to get the time from your
local server, you could run <application>daytime</application>
twice in a row: First to get the time from <systemitem class="fqdomainname">time.nist.gov</systemitem>, the second time from
your own system. You can then compare the results and see how
exact your system clock is:</para>
twice in a row: First to get the time from <systemitem
class="fqdomainname">time.nist.gov</systemitem>, the second
time from your own system. You can then compare the results
and see how exact your system clock is:</para>
<screen>&prompt.user; <userinput>daytime ; daytime localhost</userinput>
@ -1617,7 +1597,6 @@ int main(int argc, char *argv[]) {
<para>As you can see, my system was two seconds ahead of the
<acronym>NIST</acronym> time.</para>
</sect2>
<sect2 xml:id="sockets-getservbyname">
@ -1628,9 +1607,7 @@ int main(int argc, char *argv[]) {
<filename>netdb.h</filename> comes in very handy in those
cases:</para>
<programlisting>
struct servent * getservbyname(const char *name, const char *proto);
</programlisting>
<programlisting>struct servent * getservbyname(const char *name, const char *proto);</programlisting>
<para>The <varname>servent</varname> structure contains the
<varname>s_port</varname>, which contains the proper port,
@ -1640,29 +1617,25 @@ struct servent * getservbyname(const char *name, const char *proto);
<emphasis>daytime</emphasis> service, we could have found it
this way:</para>
<programlisting>
struct servent *se;
<programlisting>struct servent *se;
...
if ((se = getservbyname("daytime", "tcp")) == NULL {
fprintf(stderr, "Cannot determine which port to use.\n");
return 7;
}
sa.sin_port = se-&gt;s_port;
</programlisting>
sa.sin_port = se-&gt;s_port;</programlisting>
<para>You usually do know the port. But if you are developing a
new protocol, you may be testing it on an unofficial
port. Some day, you will register the protocol and its port
(if nowhere else, at least in your
new protocol, you may be testing it on an unofficial port.
Some day, you will register the protocol and its port (if
nowhere else, at least in your
<filename>/etc/services</filename>, which is where
<function>getservbyname</function> looks). Instead of
returning an error in the above code, you just use the
temporary port number. Once you have listed the protocol in
<filename>/etc/services</filename>, your software will find
its port without you having to rewrite the code.</para>
</sect2>
</sect1>
<sect1 xml:id="sockets-concurrent-servers">
@ -1724,13 +1697,13 @@ struct servent * getservbyname(const char *name, const char *proto);
<para>We moved the <emphasis>serve</emphasis> from the
<emphasis>daemon process</emphasis> to its own <emphasis>server
process</emphasis>. However, because each child process inherits
all open files (and a socket is treated just like a file), the
new process inherits not only the <emphasis><quote>accepted
handle,</quote></emphasis> i.e., the socket returned by the
<function>accept</function> call, but also the <emphasis>top
socket</emphasis>, i.e., the one opened by the top process right
at the beginning.</para>
process</emphasis>. However, because each child process
inherits all open files (and a socket is treated just like a
file), the new process inherits not only the
<emphasis><quote>accepted handle,</quote></emphasis> i.e., the
socket returned by the <function>accept</function> call, but
also the <emphasis>top socket</emphasis>, i.e., the one opened
by the top process right at the beginning.</para>
<para>However, the <emphasis>server process</emphasis> does not
need this socket and should <function>close</function> it
@ -1744,8 +1717,7 @@ struct servent * getservbyname(const char *name, const char *proto);
<para>After the <emphasis>server process</emphasis> is done
serving, it should close the <emphasis>accepted
socket</emphasis>. Instead of returning to
<function>accept</function>, it now exits.
</para>
<function>accept</function>, it now exits.</para>
<para>Under &unix;, a process does not really
<emphasis>exit</emphasis>. Instead, it
@ -1766,13 +1738,11 @@ struct servent * getservbyname(const char *name, const char *proto);
release the system resources they are taking up.</para>
<para>That is why our flowchart now contains a <emphasis>process
signals</emphasis> box, which is not connected to any other box.
By the way, many servers also process <symbol>SIGHUP</symbol>,
and typically interpret as the signal from the superuser that
they should reread their configuration files. This allows us to
change settings without having to kill and restart these
servers.</para>
signals</emphasis> box, which is not connected to any other
box. By the way, many servers also process
<symbol>SIGHUP</symbol>, and typically interpret as the signal
from the superuser that they should reread their configuration
files. This allows us to change settings without having to kill
and restart these servers.</para>
</sect1>
</chapter>