The translation is temporarily closed for contributions due to maintenance, please come back later.

Source string Read only

(itstool) path: sect2/para
Context English State
<prompt>%</prompt> <userinput>who</userinput>

whizkid ttyp0 Jun 19 16:59 (216.127.220.143)
xxx ttyp1 Jun 19 16:06 (xx.xx.xx.xx)
<prompt>%</prompt> <userinput>telnet 216.127.220.143 13</userinput>

Trying 216.127.220.143...
Connected to r47.bfm.org.
Escape character is '^]'.
2001-06-19T21:31:11Z
Connection closed by foreign host.
<prompt>%</prompt>
Again, it worked. Will it work using the domain name?
<prompt>%</prompt> <userinput>telnet r47.bfm.org 13</userinput>

Trying 216.127.220.143...
Connected to r47.bfm.org.
Escape character is '^]'.
2001-06-19T21:31:40Z
Connection closed by foreign host.
<prompt>%</prompt>
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 <function>fclose(client);</function> in our code works as advertised.
Helper Functions
FreeBSD C library contains many helper functions for sockets programming. For example, in our sample client we hard coded the <systemitem class="fqdomainname">time.nist.gov</systemitem> <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.
<function>gethostbyname</function>
While there is no way to pass the domain name directly to any of the sockets functions, the FreeBSD C library comes with the <citerefentry><refentrytitle>gethostbyname</refentrytitle><manvolnum>3</manvolnum></citerefentry> and <citerefentry><refentrytitle>gethostbyname2</refentrytitle><manvolnum>3</manvolnum></citerefentry> functions, declared in <filename>netdb.h</filename>.
struct hostent * gethostbyname(const char *name);
struct hostent * gethostbyname2(const char *name, int af);
Both return a pointer to the <varname>hostent</varname> structure, with much information about the domain. For our purposes, the <varname>h_addr_list[0]</varname> field of the structure points at <varname>h_length</varname> bytes of the correct address, already stored in the <emphasis>network byte order</emphasis>.
This allows us to create a much more flexible—and much more useful—version of our <application>daytime</application> program:
/*
* daytime.c
*
* Programmed by G. Adam Stanislav
* 19 June 2001
*/
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;netinet/in.h&gt;
#include &lt;netdb.h&gt;

int main(int argc, char *argv[]) {
register int s;
register int bytes;
struct sockaddr_in sa;
struct hostent *he;
char buf[BUFSIZ+1];
char *host;

if ((s = socket(PF_INET, SOCK_STREAM, 0)) &lt; 0) {
perror("socket");
return 1;
}

bzero(&amp;sa, sizeof sa);

sa.sin_family = AF_INET;
sa.sin_port = htons(13);

host = (argc &gt; 1) ? (char *)argv[1] : "time.nist.gov";

if ((he = gethostbyname(host)) == NULL) {
herror(host);
return 2;
}

bcopy(he-&gt;h_addr_list[0],&amp;sa.sin_addr, he-&gt;h_length);

if (connect(s, (struct sockaddr *)&amp;sa, sizeof sa) &lt; 0) {
perror("connect");
return 3;
}

while ((bytes = read(s, buf, BUFSIZ)) &gt; 0)
write(1, buf, bytes);

close(s);
return 0;
}
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.
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:
<prompt>%</prompt> <userinput>daytime ; daytime localhost</userinput>


52080 01-06-20 04:02:33 50 0 0 390.2 UTC(NIST) *
2001-06-20T04:02:35Z
<prompt>%</prompt>
As you can see, my system was two seconds ahead of the <acronym>NIST</acronym> time.
<function>getservbyname</function>
Sometimes you may not be sure what port a certain service uses. The <citerefentry><refentrytitle>getservbyname</refentrytitle><manvolnum>3</manvolnum></citerefentry> function, also declared in <filename>netdb.h</filename> comes in very handy in those cases:
struct servent * getservbyname(const char *name, const char *proto);
The <varname>servent</varname> structure contains the <varname>s_port</varname>, which contains the proper port, already in <emphasis>network byte order</emphasis>.
Had we not known the correct port for the <emphasis>daytime</emphasis> service, we could have found it this way:
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;
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 <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.
Concurrent Servers
Unlike a sequential server, a <emphasis>concurrent server</emphasis> has to be able to serve more than one client at a time. For example, a <emphasis>chat server</emphasis> may be serving a specific client for hours—it cannot wait till it stops serving a client before it serves the next one.
This requires a significant change in our flowchart:
_ external ref='sockets/serv2' md5='__failed__'
+-----------------+
| Create Socket |
+-----------------+
|
+-----------------+
| Bind Port | Daemon Process
+-----------------+
| +--------+
+-------------+--&gt;| Init |
| | +--------+
+-----------------+ | |
| Exit | | +--------+
+-----------------+ | | Listen |
| +--------+
| |
| +--------+
| | Accept |
| +--------+
| | +------------------+
| +------&gt;| Close Top Socket |
| | +------------------+
| +--------+ |
| | Close | +------------------+
| +--------+ | Serve |
| | +------------------+
|&lt;--------+ |
+------------------+
| Close Acc Socket |
+--------+ +------------------+
| Signal | |
+--------+ +------------------+
| Exit |
+------------------+
<imageobject> <imagedata fileref="sockets/serv2"/> </imageobject> <textobject> <_:literallayout-1/> </textobject> <textobject> <phrase>Concurrent Server</phrase> </textobject>
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.
However, the <emphasis>server process</emphasis> does not need this socket and should <function>close</function> it immediately. Similarly, the <emphasis>daemon process</emphasis> no longer needs the <emphasis>accepted socket</emphasis>, and not only should, but <emphasis>must</emphasis> <function>close</function> it—otherwise, it will run out of available <emphasis>file descriptors</emphasis> sooner or later.

Loading…

No matching activity found.

Browse all component changes

Source information

Source string comment
(itstool) path: sect2/para
Flags
read-only
Source string location
book.translate.xml:6493
String age
a year ago
Source string age
a year ago
Translation file
books/developers-handbook.pot, string 1049