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