epubjs
Version:
Render ePub documents in the browser, across many devices
381 lines (364 loc) • 79.9 kB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Sockets</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="Sockets"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-13-SECT-1"/>Sockets</h1></div></div></div><p>Sockets are a low-level programming interface for networked
communications. They send streams of data between applications that may or
may not be on the same host. Sockets originated in BSD Unix
and are, in some programming languages, hairy, complicated things with
lots of small parts that can break off and endanger little children. The
reason for this is that most socket APIs can be used with almost any kind
of underlying network protocol. Since the protocols that transport data
across the network can have radically different features, the socket
interface can be quite complex.<sup>[<a id="learnjava3-CHP-13-FN-1" href="#ftn.learnjava3-CHP-13-FN-1" class="footnote">37</a>]</sup></p><p>The <a id="I_indexterm13_id764911" class="indexterm"/><code class="literal">java.net</code> package supports
a simplified, object-oriented socket interface that makes network
communications considerably easier. If you’ve done network programming
using sockets in other languages, you should be pleasantly surprised at
how simple things can be when objects encapsulate the gory details. If
this is the first time you’ve come across sockets, you’ll find that
talking to another application over the network can be as simple as
reading a file or getting user input. Most forms of I/O in Java, including
most network I/O, use the stream classes described in <a class="xref" href="ch12.html" title="Chapter 12. Input/Output Facilities">Chapter 12</a>. Streams provide a unified I/O interface so
that reading or writing across the Internet is similar to reading or
writing on the local system. In addition to the stream-oriented
interfaces, the Java networking APIs can work with the Java NIO
buffer-oriented API for highly scalable applications. We’ll see both in
this chapter.</p><p>Java provides sockets to support three distinct classes of
underlying protocols: <code class="literal">Socket</code>s,
<a id="I_indexterm13_id764947" class="indexterm"/><code class="literal">DatagramSocket</code>s, and
<a id="I_indexterm13_id764958" class="indexterm"/><code class="literal">MulticastSocket</code>s. In this
first section, we look at Java’s basic <code class="literal">Socket</code> class, which uses a <a id="I_indexterm13_id764975" class="indexterm"/><span class="emphasis"><em>connection-oriented</em></span> and
<span class="emphasis"><em>reliable</em></span> protocol. A connection-oriented protocol
provides the equivalent of a telephone conversation. After establishing a
connection, two applications can send streams of data back and forth and
the connection stays in place even when no one is talking. Because the
protocol is reliable, it also ensures that no data is lost (resending data
as necessary) and that whatever you send always arrives in the order in
which you sent it.</p><p>In the next section, we look at the <code class="literal">DatagramSocket</code> class, which uses a <a id="I_indexterm13_id764999" class="indexterm"/><span class="emphasis"><em>connectionless</em></span>,
<span class="emphasis"><em>unreliable</em></span> protocol. A connectionless protocol is
like the postal service. Applications can send short messages to each
other, but no end-to-end connection is set up in advance and no attempt is
made to keep the messages in order. It’s not even guaranteed that the
messages will arrive at all. A <a id="I_indexterm13_id765016" class="indexterm"/><code class="literal">MulticastSocket</code> is a
variation of a <code class="literal">DatagramSocket</code> that
performs multicasting—simultaneously sending data to multiple recipients.
Working with multicast sockets is very much like working with datagram
sockets. However, because multicasting is currently not widely supported
across the Internet, we do not cover it here.</p><p>In theory, just about any protocol can be used underneath the socket
layer (old-schoolers will remember things like Novell’s IPX, Apple’s
AppleTalk, etc.). But in practice, there’s only one important protocol
family used on the Internet, and only one protocol family that Java
supports: the <a id="I_indexterm13_id765045" class="indexterm"/><a id="I_indexterm13_id765050" class="indexterm"/>Internet Protocol (IP). The <a id="I_indexterm13_id765057" class="indexterm"/><a id="I_indexterm13_id765062" class="indexterm"/><a id="I_indexterm13_id765068" class="indexterm"/><code class="literal">Socket</code> class speaks TCP,
the connection-oriented flavor of IP, and the <a id="I_indexterm13_id765080" class="indexterm"/><a id="I_indexterm13_id765085" class="indexterm"/><a id="I_indexterm13_id765091" class="indexterm"/><code class="literal">DatagramSocket</code> class
speaks UDP, the connectionless kind.</p><div class="sect2" title="Clients and Servers"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-13-SECT-1.1"/>Clients and Servers</h2></div></div></div><p>When writing network applications, it’s common to talk about
clients and servers. The distinction is increasingly vague, but the side
that initiates the conversation is usually considered the
<span class="emphasis"><em>client</em></span>. The side that accepts the request is
usually the <span class="emphasis"><em>server</em></span>. In the case where two peer
applications use sockets to talk, the distinction is less important, but
for simplicity we’ll use this definition.</p><p>For our purposes, the most important difference between a client
and a server is that a client can create a socket to initiate a
conversation with a server application at any time, while a server must
be prepared in advance to listen for incoming conversations. The
<code class="literal">java.net.Socket</code> class represents one
side of an individual socket connection on both the client and server.
In addition, the server uses the <a id="I_indexterm13_id765135" class="indexterm"/><code class="literal">java.net.ServerSocket</code>
class to listen for new connections from clients. In most cases, an
application acting as a server creates a <code class="literal">ServerSocket</code> object and waits, blocked in a
call to its <a id="I_indexterm13_id765153" class="indexterm"/><code class="literal">accept()</code> method, until
a connection arrives. When it arrives, the <code class="literal">accept()</code> method creates a <code class="literal">Socket</code> object that the server uses to
communicate with the client. A server may carry on conversations with
multiple clients at once; in this case, there is still only a single
<code class="literal">ServerSocket</code>, but the server has
multiple <code class="literal">Socket</code> objects—one
associated with each client, as shown in <a class="xref" href="ch13s01.html#learnjava3-CHP-13-FIG-2" title="Figure 13-2. Clients and servers, Sockets and ServerSockets">Figure 13-2</a>.</p><p>At the socket level, a client needs two pieces of information to
locate and connect to a server on the Internet: a
<span class="emphasis"><em>hostname</em></span> (used to find the host computer’s network
address) and a <span class="emphasis"><em>port number</em></span>. The port number is an
identifier that differentiates between multiple clients or servers on
the same host. A server application listens on a prearranged port while
waiting for connections. Clients use the port number assigned to the
service they want to access. If you think of the host computers as
hotels and the applications as guests, the ports are like the guests’
room numbers. For one person to call another, he or she must know the
other party’s hotel name and room number.</p><div class="figure"><a id="learnjava3-CHP-13-FIG-2"/><div class="figure-contents"><div class="mediaobject"><a id="I_13_tt835"/><img src="httpatomoreillycomsourceoreillyimages1707645.png" alt="Clients and servers, Sockets and ServerSockets"/></div></div><p class="title">Figure 13-2. Clients and servers, Sockets and ServerSockets</p></div><div class="sect3" title="Clients"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-13-SECT-1.1.1"/>Clients</h3></div></div></div><p><a id="idx10760" class="indexterm"/> <a id="idx10780" class="indexterm"/> <a id="idx10805" class="indexterm"/>A client application opens a connection to a server by
constructing a <a id="I_indexterm13_id765277" class="indexterm"/><code class="literal">Socket</code> that specifies
the hostname and port number of the desired server:</p><a id="I_13_tt836"/><pre class="programlisting"> <code class="k">try</code> <code class="o">{</code>
<code class="n">Socket</code> <code class="n">sock</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Socket</code><code class="o">(</code><code class="s">"wupost.wustl.edu"</code><code class="o">,</code> <code class="mi">25</code><code class="o">);</code>
<code class="o">}</code> <code class="k">catch</code> <code class="o">(</code> <code class="n">UnknownHostException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"Can't find host."</code><code class="o">);</code>
<code class="o">}</code> <code class="k">catch</code> <code class="o">(</code> <code class="n">IOException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"Error connecting to host."</code><code class="o">);</code>
<code class="o">}</code></pre><p>This code fragment attempts to connect a <code class="literal">Socket</code> to port 25 (the SMTP mail service) of
the host <span class="emphasis"><em>wupost.wustl.edu</em></span>. The client handles the
possibility that the hostname can’t be resolved (<code class="literal">UnknownHostException</code>) and that it might not
be able to connect to it (<code class="literal">IOException</code>). In the preceding case, Java
used DNS, the standard Domain Name Service, to resolve the hostname to
an IP address for us. The constructor can also accept a string
containing the host’s raw IP address:</p><a id="I_13_tt837"/><pre class="programlisting"> <code class="n">Socket</code> <code class="n">sock</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Socket</code><code class="o">(</code><code class="s">"22.66.89.167"</code><code class="o">,</code> <code class="mi">25</code><code class="o">);</code></pre><p>After a connection is made, input and output streams can be
retrieved with the <code class="literal">Socket
getInputStream()</code> and <a id="I_indexterm13_id765344" class="indexterm"/><code class="literal">getOutputStream()</code>
methods. The following (rather arbitrary) code sends and receives some
data with the streams:</p><a id="I_13_tt838"/><pre class="programlisting"> <code class="k">try</code> <code class="o">{</code>
<code class="n">Socket</code> <code class="n">server</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Socket</code><code class="o">(</code><code class="s">"foo.bar.com"</code><code class="o">,</code> <code class="mi">1234</code><code class="o">);</code>
<code class="n">InputStream</code> <code class="n">in</code> <code class="o">=</code> <code class="n">server</code><code class="o">.</code><code class="na">getInputStream</code><code class="o">();</code>
<code class="n">OutputStream</code> <code class="n">out</code> <code class="o">=</code> <code class="n">server</code><code class="o">.</code><code class="na">getOutputStream</code><code class="o">();</code>
<code class="c1">// write a byte</code>
<code class="n">out</code><code class="o">.</code><code class="na">write</code><code class="o">(</code><code class="mi">42</code><code class="o">);</code>
<code class="c1">// write a newline or carriage return delimited string</code>
<code class="n">PrintWriter</code> <code class="n">pout</code> <code class="o">=</code> <code class="k">new</code> <code class="n">PrintWriter</code><code class="o">(</code> <code class="n">out</code><code class="o">,</code> <code class="kc">true</code> <code class="o">);</code>
<code class="n">pout</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"Hello!"</code><code class="o">);</code>
<code class="c1">// read a byte</code>
<code class="kt">byte</code> <code class="n">back</code> <code class="o">=</code> <code class="o">(</code><code class="kt">byte</code><code class="o">)</code><code class="n">in</code><code class="o">.</code><code class="na">read</code><code class="o">();</code>
<code class="c1">// read a newline or carriage return delimited string</code>
<code class="n">BufferedReader</code> <code class="n">bin</code> <code class="o">=</code>
<code class="k">new</code> <code class="nf">BufferedReader</code><code class="o">(</code> <code class="k">new</code> <code class="n">InputStreamReader</code><code class="o">(</code> <code class="n">in</code> <code class="o">)</code> <code class="o">);</code>
<code class="n">String</code> <code class="n">response</code> <code class="o">=</code> <code class="n">bin</code><code class="o">.</code><code class="na">readLine</code><code class="o">();</code>
<code class="c1">// send a serialized Java object</code>
<code class="n">ObjectOutputStream</code> <code class="n">oout</code> <code class="o">=</code> <code class="k">new</code>
<code class="n">ObjectOutputStream</code><code class="o">(</code> <code class="n">out</code> <code class="o">);</code>
<code class="n">oout</code><code class="o">.</code><code class="na">writeObject</code><code class="o">(</code> <code class="k">new</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">Date</code><code class="o">()</code> <code class="o">);</code>
<code class="n">oout</code><code class="o">.</code><code class="na">flush</code><code class="o">();</code>
<code class="err"> </code>
<code class="n">server</code><code class="o">.</code><code class="na">close</code><code class="o">();</code>
<code class="o">}</code>
<code class="k">catch</code> <code class="o">(</code><code class="n">IOException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code></pre><p>In this exchange, the client first creates a <code class="literal">Socket</code> for communicating with the server.
The <code class="literal">Socket</code> constructor specifies
the server’s hostname (<span class="emphasis"><em>foo.bar.com</em></span>) and a
prearranged port number (1234). Once the connection is established,
the client writes a single byte to the server using the <code class="literal">OutputStream</code>’s <code class="literal">write()</code> method. To send a string of text
more easily, it then wraps a <code class="literal">PrintWriter</code> around the <code class="literal">OutputStream</code>. Next, it performs the
complementary operations: reading a byte back from the server using
<code class="literal">InputStream</code>’s <code class="literal">read()</code> method and then creating a <code class="literal">BufferedReader</code> from which to get a full
string of text. Finally, we do something really funky and send a
serialized Java object to the server, using an <code class="literal">ObjectOutputStream</code>. (We’ll talk in depth
about sending serialized objects later in this chapter.) The client
then terminates the connection with the <code class="literal">close()</code> method. All these operations have
the potential to generate <a id="I_indexterm13_id765453" class="indexterm"/><code class="literal">IOException</code>s; our
application will deal with these using the <code class="literal">catch</code> clause.<a id="I_indexterm13_id765469" class="indexterm"/><a id="I_indexterm13_id765476" class="indexterm"/><a id="I_indexterm13_id765483" class="indexterm"/></p></div><div class="sect3" title="Servers"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-13-SECT-1.1.2"/>Servers</h3></div></div></div><p><a id="idx10785" class="indexterm"/> <a id="idx10803" class="indexterm"/> <a id="idx10808" class="indexterm"/>After a connection is established, a server application
uses the same kind of <code class="literal">Socket</code> object
for its side of the communications. However, to accept a connection
from a client, it must first create a <a id="I_indexterm13_id765542" class="indexterm"/><code class="literal">ServerSocket</code>, bound
to the correct port. Let’s recreate the previous conversation from the
server’s point of view:</p><a id="I_13_tt839"/><pre class="programlisting"> <code class="c1">// Meanwhile, on foo.bar.com...</code>
<code class="k">try</code> <code class="o">{</code>
<code class="n">ServerSocket</code> <code class="n">listener</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ServerSocket</code><code class="o">(</code> <code class="mi">1234</code> <code class="o">);</code>
<code class="k">while</code> <code class="o">(</code> <code class="o">!</code><code class="n">finished</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">Socket</code> <code class="n">client</code> <code class="o">=</code> <code class="n">listener</code><code class="o">.</code><code class="na">accept</code><code class="o">();</code> <code class="c1">// wait for connection</code>
<code class="n">InputStream</code> <code class="n">in</code> <code class="o">=</code> <code class="n">client</code><code class="o">.</code><code class="na">getInputStream</code><code class="o">();</code>
<code class="n">OutputStream</code> <code class="n">out</code> <code class="o">=</code> <code class="n">client</code><code class="o">.</code><code class="na">getOutputStream</code><code class="o">();</code>
<code class="c1">// read a byte</code>
<code class="kt">byte</code> <code class="n">someByte</code> <code class="o">=</code> <code class="o">(</code><code class="kt">byte</code><code class="o">)</code><code class="n">in</code><code class="o">.</code><code class="na">read</code><code class="o">();</code>
<code class="c1">// read a newline or carriage-return-delimited string</code>
<code class="n">BufferedReader</code> <code class="n">bin</code> <code class="o">=</code>
<code class="k">new</code> <code class="nf">BufferedReader</code><code class="o">(</code> <code class="k">new</code> <code class="n">InputStreamReader</code><code class="o">(</code> <code class="n">in</code> <code class="o">)</code> <code class="o">);</code>
<code class="n">String</code> <code class="n">someString</code> <code class="o">=</code> <code class="n">bin</code><code class="o">.</code><code class="na">readLine</code><code class="o">();</code>
<code class="c1">// write a byte</code>
<code class="n">out</code><code class="o">.</code><code class="na">write</code><code class="o">(</code><code class="mi">43</code><code class="o">);</code>
<code class="c1">// say goodbye</code>
<code class="n">PrintWriter</code> <code class="n">pout</code> <code class="o">=</code> <code class="k">new</code> <code class="n">PrintWriter</code><code class="o">(</code> <code class="n">out</code><code class="o">,</code> <code class="kc">true</code> <code class="o">);</code>
<code class="n">pout</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"Goodbye!"</code><code class="o">);</code>
<code class="err"> </code>
<code class="c1">// read a serialized Java object</code>
<code class="n">ObjectInputStream</code> <code class="n">oin</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ObjectInputStream</code><code class="o">(</code> <code class="n">in</code> <code class="o">);</code>
<code class="n">Date</code> <code class="n">date</code> <code class="o">=</code> <code class="o">(</code><code class="n">Date</code><code class="o">)</code><code class="n">oin</code><code class="o">.</code><code class="na">readObject</code><code class="o">();</code>
<code class="n">client</code><code class="o">.</code><code class="na">close</code><code class="o">();</code>
<code class="o">}</code>
<code class="n">listener</code><code class="o">.</code><code class="na">close</code><code class="o">();</code>
<code class="o">}</code>
<code class="k">catch</code> <code class="o">(</code><code class="n">IOException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code>
<code class="k">catch</code> <code class="o">(</code><code class="n">ClassNotFoundException</code> <code class="n">e2</code> <code class="o">)</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code></pre><p>First, our server creates a <code class="literal">ServerSocket</code> attached to port 1234. On some
systems, there are rules about which ports an application can use.
Port numbers below 1024 are usually reserved for system processes and
standard, <span class="emphasis"><em>well-known</em></span> services, so we pick a port
number outside of this range. The <code class="literal">ServerSocket</code> is created only once;
thereafter, we can accept as many connections as arrive.</p><p>Next, we enter a loop, waiting for the <a id="I_indexterm13_id765603" class="indexterm"/><code class="literal">accept()</code> method of
the <code class="literal">ServerSocket</code> to return an
active <code class="literal">Socket</code> connection from a
client. When a connection has been established, we perform the server
side of our dialog, then close the connection and return to the top of
the loop to wait for another connection. Finally, when the server
application wants to stop listening for connections altogether, it
calls the <code class="literal">close()</code> method of the
<code class="literal">ServerSocket</code>.</p><p>This server is single-threaded; it handles one connection at a
time, not calling <code class="literal">accept()</code> to
listen for a new connection until it’s finished with the current
connection. A more realistic server would have a loop that accepts
connections concurrently and passes them off to their own threads for
processing. There is a lot to be said about implementing multithreaded
servers. Later in this chapter, we’ll create a tiny web server that
starts a new thread for each connection and also a slightly more
complex web server that uses the NIO package to handle many
connections with a small number of threads.<a id="I_indexterm13_id765652" class="indexterm"/><a id="I_indexterm13_id765659" class="indexterm"/><a id="I_indexterm13_id765666" class="indexterm"/></p></div><div class="sect3" title="Sockets and security"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-13-SECT-1.1.3"/>Sockets and security</h3></div></div></div><p><a id="idx10784" class="indexterm"/> <a id="idx10802" class="indexterm"/> <a id="I_indexterm13_id765708" class="indexterm"/>The previous examples presuppose that the client has
permission to connect to the server and that the server is allowed to
listen on the specified socket. If you’re writing a general,
standalone application, this is normally the case (and you can
probably skip this section). However, untrusted applications (such as
Java applets in a web browser) run under the auspices of a security
policy that can impose arbitrary restrictions on what hosts they may
or may not talk to and whether or not they can listen for connections.</p><p>For example, the security policy imposed on applets by most
browsers allow untrusted applets to open socket connections only to
the host that served them—that is, they can talk back only to the
server from which their class files were retrieved. Untrusted applets
are generally not allowed to open server sockets for incoming
connections themselves. This doesn’t mean that an untrusted applet
can’t cooperate with its server to communicate with anyone, anywhere.
The applet’s server could run a proxy that lets the applet communicate
indirectly with anyone it likes. What this security policy prevents is
malicious applets poking around inside corporate firewalls, making
connections to trusted services. It places the burden of security on
the originating server, not the client machine. Restricting access to
the originating server limits the usefulness of Trojan applications
that do annoying things from the client side. (You probably won’t let
your proxy spam people, because you’ll be blamed.)</p><p>If you are going to run your own application under a security
manager, you should be aware that the default security manager
dissallows all network access. So in order to make network
connections, you would have to modify your policy file to grant the
appropriate permissions to your code (see <a class="xref" href="ch03.html" title="Chapter 3. Tools of the Trade">Chapter 3</a> for details). The following policy file
fragment sets the socket permissions to allow connections to or from
any host on any nonprivileged port:</p><a id="I_13_tt840"/><pre class="programlisting"> <code class="n">grant</code> <code class="o">{</code>
<code class="n">permission</code> <code class="n">java</code><code class="o">.</code><code class="na">net</code><code class="o">.</code><code class="na">SocketPermission</code>
<code class="s">"*:1024-"</code><code class="o">,</code> <code class="s">"listen,accept,connect"</code><code class="o">;</code>
<code class="o">};</code></pre><p>When starting the Java interpreter, you can install the security
manager and use this file (call it
<span class="emphasis"><em>mysecurity.policy</em></span>):<a id="I_indexterm13_id765779" class="indexterm"/><a id="I_indexterm13_id765786" class="indexterm"/></p><a id="I_13_tt841"/><pre class="programlisting"> <code class="o">%</code> <strong class="userinput"><code><code class="n">java</code> <code class="o">-</code><code class="n">Djava</code><code class="o">.</code><code class="na">security</code><code class="o">.</code><code class="na">manager</code>
<code class="err">\</code></code></strong><strong class="userinput"><code><code class="o">-</code><code class="n">Djava</code><code class="o">.</code><code class="na">security</code><code class="o">.</code><code class="na">policy</code><code class="o">=</code><code class="n">mysecurity</code><code class="o">.</code><code class="na">policy</code> <code class="n">MyApplication</code></code></strong></pre></div></div><div class="sect2" title="author="pat” timestamp="20120926T110720-0500” comment="one of those sections I hate to get rid of but is less relevant in terms of the example... should probably find a more modern example...”The DateAtHost Client"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-13-SECT-1.2"/>The DateAtHost Client</h2></div></div></div><p><a id="idx10765" class="indexterm"/> <a id="idx10781" class="indexterm"/> <a id="idx10806" class="indexterm"/>In the past, many networked computers ran a simple time
service that dispensed their clock’s local time on a well-known port.
This was a precursor of NTP, the more general Network Time Protocol. The
next example, <code class="literal">DateAtHost</code>, includes a
subclass of <code class="literal">java.util.Date</code> that
fetches the time from a remote host instead of initializing itself from
the local clock. (See <a class="xref" href="ch11.html" title="Chapter 11. Core Utilities">Chapter 11</a> for a
complete discussion of the <code class="literal">Date</code>
class.)</p><p><code class="literal">DateAtHost</code> connects to the time
service (port 37) and reads four bytes representing the time on the
remote host. These four bytes have a peculiar specification that we
decode to get the time. Here’s the code:</p><a id="I_13_tt842"/><pre class="programlisting"> <code class="c1">//file: DateAtHost.java</code>
<code class="kn">import</code> <code class="nn">java.net.Socket</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.io.*</code><code class="o">;</code>
<code class="err"> </code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">DateAtHost</code> <code class="kd">extends</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">Date</code> <code class="o">{</code>
<code class="kd">static</code> <code class="kt">int</code> <code class="n">timePort</code> <code class="o">=</code> <code class="mi">37</code><code class="o">;</code>
<code class="c1">// seconds from start of 20th century to Jan 1, 1970 00:00 GMT</code>
<code class="kd">static</code> <code class="kd">final</code> <code class="kt">long</code> <code class="n">offset</code> <code class="o">=</code> <code class="mi">2208988800L</code><code class="o">;</code>
<code class="kd">public</code> <code class="nf">DateAtHost</code><code class="o">(</code> <code class="n">String</code> <code class="n">host</code> <code class="o">)</code> <code class="kd">throws</code> <code class="n">IOException</code> <code class="o">{</code>
<code class="k">this</code><code class="o">(</code> <code class="n">host</code><code class="o">,</code> <code class="n">timePort</code> <code class="o">);</code>
<code class="o">}</code>
<code class="err"> </code>
<code class="kd">public</code> <code class="nf">DateAtHost</code><code class="o">(</code> <code class="n">String</code> <code class="n">host</code><code class="o">,</code> <code class="kt">int</code> <code class="n">port</code> <code class="o">)</code> <code class="kd">throws</code> <code class="n">IOException</code> <code class="o">{</code>
<code class="n">Socket</code> <code class="n">server</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Socket</code><code class="o">(</code> <code class="n">host</code><code class="o">,</code> <code class="n">port</code> <code class="o">);</code>
<code class="n">DataInputStream</code> <code class="n">din</code> <code class="o">=</code>
<code class="k">new</code> <code class="nf">DataInputStream</code><code class="o">(</code> <code class="n">server</code><code class="o">.</code><code class="na">getInputStream</code><code class="o">()</code> <code class="o">);</code>
<code class="kt">int</code> <code class="n">time</code> <code class="o">=</code> <code class="n">din</code><code class="o">.</code><code class="na">readInt</code><code class="o">();</code>
<code class="n">server</code><code class="o">.</code><code class="na">close</code><code class="o">();</code>
<code class="n">setTime</code><code class="o">(</code> <code class="o">(((</code><code class="mi">1L</code> <code class="o"><<</code> <code class="mi">32</code><code class="o">)</code> <code class="o">+</code> <code class="n">time</code><code class="o">)</code> <code class="o">-</code> <code class="n">offset</code><code class="o">)</code> <code class="o">*</code> <code class="mi">1000</code> <code class="o">);</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>That’s all there is to it. It’s not very long, even with a few
frills. We have supplied two possible constructors for <code class="literal">DateAtHost</code>. Normally we’d expect to use the
first, which simply takes the name of the remote host as an argument.
The second constructor specifies the hostname and the port number of the
remote time service. (If the time service were running on a nonstandard
port, we would use the second constructor to specify the alternate port
number.) This second constructor does the work of making the connection
and setting the time. The first constructor simply invokes the second
(using the <code class="literal">this()</code> construct) with the
default port as an argument. Supplying simplified constructors that
invoke their siblings with default arguments is a common and useful
pattern in Java; that is the main reason we’ve shown it here.</p><p>The second constructor opens a socket to the specified port on the
remote host. It creates a <a id="I_indexterm13_id765947" class="indexterm"/><code class="literal">DataInputStream</code> to wrap
the input stream and then reads a four-byte integer using the <a id="I_indexterm13_id765959" class="indexterm"/><code class="literal">readInt()</code> method. It’s
no coincidence that the bytes are in the right order. Java’s <code class="literal">DataInputStream</code> and <code class="literal">DataOutputStream</code> classes work with the bytes
of integer types in <span class="emphasis"><em>network byte order</em></span> (most
significant to least significant). The time protocol (and other standard
network protocols that deal with binary data) also uses the network byte
order, so we don’t need to call any conversion routines. Explicit data
conversions would probably be necessary if we were using a nonstandard
protocol, especially when talking to a non-Java client or server. In
that case, we’d have to read byte by byte and do some rearranging to get
our four-byte value. After reading the data, we’re finished with the
socket, so we close it, terminating the connection to the server.
Finally, the constructor initializes the rest of the object by calling
<code class="literal">Date</code>’s <a id="I_indexterm13_id765999" class="indexterm"/><code class="literal">setTime()</code> method with
the calculated time value.</p><p>The four bytes of the time value are interpreted as an integer
representing the number of seconds since the beginning of the 20th
century. <code class="literal">DateAtHost</code> converts this to
Java’s notion of absolute time—the count of milliseconds since January
1, 1970 (an arbitrary date standardized by C and Unix). The conversion
first creates a <code class="literal">long</code> value, which is
the unsigned equivalent of the integer <code class="literal">time</code>. It subtracts an offset to make the time
relative to the epoch (January 1, 1970) rather than the century, and
multiplies by 1,000 to convert to milliseconds. The converted time is
used to initialize the object.</p><p>The <code class="literal">DateAtHost</code> class can work
with a time retrieved from a remote host almost as easily as <code class="literal">Date</code> is used with the time on the local host.
The only additional overhead is dealing with the possible <a id="I_indexterm13_id766050" class="indexterm"/><code class="literal">IOException</code> that can be
thrown by the <code class="literal">DateAtHost</code>
constructor:</p><a id="I_13_tt843"/><pre class="programlisting"> <code class="k">try</code> <code class="o">{</code>
<code class="n">Date</code> <code class="n">d</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DateAtHost</code><code class="o">(</code> <code class="s">"someserver.net"</code> <code class="o">);</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="s">"The time over there is: "</code> <code class="o">+</code> <code class="n">d</code> <code class="o">);</code>
<code class="o">}</code>
<code class="k">catch</code> <code class="o">(</code> <code class="n">IOException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code></pre><p>This example fetches the time at the host
<span class="emphasis"><em>someserver.net</em></span> and prints its value.<a id="I_indexterm13_id766082" class="indexterm"/><a id="I_indexterm13_id766089" class="indexterm"/><a id="I_indexterm13_id766096" class="indexterm"/></p></div><div class="sect2" title="The TinyHttpd Server"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-13-SECT-1.3"/>The TinyHttpd Server</h2></div></div></div><p><a id="idx10786" class="indexterm"/> <a id="idx10809" class="indexterm"/> <a id="idx10810" class="indexterm"/>Have you ever wanted to write your very own web server?
Well, you’re in luck. In this section, we’re going to build <code class="literal">TinyHttpd</code>, a minimal but functional web
server. <code class="literal">TinyHttpd</code> listens on a
specified port and services simple HTTP <code class="literal">GET</code> requests. <code class="literal">GET</code> requests are simple text commands that
look something like this:</p><a id="I_13_tt844"/><pre class="programlisting"> <code class="n">GET</code> <code class="o">/</code><em class="replaceable"><code><code class="n">path</code></code></em><code class="o">/</code><em class="replaceable"><code><code class="n">filename</code></code></em> <code class="o">[</code> <em class="replaceable"><code><code class="n">optional</code> <code class="n">stuff</code></code></em> <code class="o">]</code></pre><p>Your web browser sends one or more of these requests for each
document it retrieves from a web server. Upon reading a request, our
server attempts to open the specified file and send its contents. If
that document contains references to images or other items to be
displayed inline, the browser follows up with additional <code class="literal">GET</code> requests. For best performance, <code class="literal">TinyHttpd</code> services each request in its own
thread. Therefore, <code class="literal">TinyHttpd</code> can service several requests
concurrently.</p><p>This example works, but it’s a bit oversimplified. First, it
implements a very old subset of the HTTP protocol, so some browsers may
turn their nose up at it. (I tested this in Safari on my Mac at the time
of this writing and it worked well enough for this example’s purposes.)
Also remember that file pathnames are still somewhat
architecture-dependent in Java. This example should work as it is on
most systems, but would require some enhancement to be more robust. It’s
possible to write slightly more elaborate code that uses the
environmental information provided by Java to tailor itself to the local
system. (<a class="xref" href="ch12.html" title="Chapter 12. Input/Output Facilities">Chapter 12</a> gives some hints about
how.)</p><div class="warning" title="Warning"><h3 class="title"><a id="learnjava3-CHP-13-NOTE-5"/>Warning</h3><p>Unless you have a firewall or other security in place, the next
example serves files from your host without protection. Don’t try this
at work!</p></div><p>Now, without further ado, here’s <code class="literal">TinyHttpd</code>:</p><a id="I_13_tt845"/><pre class="programlisting"> <code class="c1">//file: TinyHttpd.java</code>
<code class="kn">import</code> <code class="nn">java.net.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.io.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.util.regex.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.util.concurrent.*</code><code class="o">;</code>
<code class="err"> </code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">TinyHttpd</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code> <code class="n">String</code> <code class="n">argv</code><code class="o">[]</code> <code class="o">)</code> <code class="kd">throws</code> <code class="n">IOException</code> <code class="o">{</code>
<code class="n">Executor</code> <code class="n">executor</code> <code class="o">=</code> <code class="n">Executors</code><code class="o">.</code><code class="na">newFixedThreadPool</code><code class="o">(</code><code class="mi">3</code><code class="o">);</code>
<code class="n">ServerSocket</code> <code class="n">ss</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ServerSocket</code><code class="o">(</code> <code class="n">Integer</code><code class="o">.</code><code class="na">parseInt</code><code class="o">(</code><code class="n">argv</code><code class="o">[</code><code class="mi">0</code><code class="o">])</code> <code class="o">);</code>
<code class="k">while</code> <code class="o">(</code> <code class="kc">true</code> <code class="o">)</code>
<code class="n">executor</code><code class="o">.</code><code class="na">execute</code><code class="o">(</code> <code class="k">new</code> <code class="n">TinyHttpdConnection</code><code class="o">(</code> <code class="n">ss</code><code class="o">.</code><code class="na">accept</code><code class="o">()</code> <code class="o">)</code> <code class="o">);</code>
<code class="o">}</code>
<code class="o">}</code>
<code class="kd">class</code> <code class="nc">TinyHttpdConnection</code> <code class="kd">implements</code> <code class="n">Runnable</code> <code class="o">{</code>
<code class="n">Socket</code> <code class="n">client</code><code class="o">;</code>
<code class="n">TinyHttpdConnection</code> <code class="o">(</code> <code class="n">Socket</code> <code class="n">client</code> <code class="o">)</code> <code class="kd">throws</code> <code class="n">SocketException</code> <code class="o">{</code>
<code class="k">this</code><code class="o">.</code><code class="na">client</code> <code class="o">=</code> <code class="n">client</code><code class="o">;</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">run</code><code class="o">()</code> <code class="o">{</code>
<code class="k">try</code> <code class="o">{</code>
<code class="n">BufferedReader</code> <code class="n">in</code> <code class="o">=</code> <code class="k">new</code> <code class="n">BufferedReader</code><code class="o">(</code>
<code class="k">new</code> <code class="nf">InputStreamReader</code><code class="o">(</code><code class="n">client</code><code class="o">.</code><code class="na">getInputStream</code><code class="o">(),</code> <code class="s">"8859_1"</code> <code class="o">)</code> <code class="o">);</code>
<code class="n">OutputStream</code> <code class="n">out</code> <code class="o">=</code> <code class="n">client</code><code class="o">.</code><code class="na">getOutputStream</code><code class="o">();</code>
<code class="n">PrintWriter</code> <code class="n">pout</code> <code class="o">=</code> <code class="k">new</code> <code class="n">PrintWriter</code><code class="o">(</code>
<code class="k">new</code> <code class="nf">OutputStreamWriter</code><code class="o">(</code><code class="n">out</code><code class="o">,</code> <code class="s">"8859_1"</code><code class="o">),</code> <code class="kc">true</code> <code class="o">);</code>
<code class="n">String</code> <code class="n">request</code> <code class="o">=</code> <code class="n">in</code><code class="o">.</code><code class="na">readLine</code><code class="o">();</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="s">"Request: "</code><code class="o">+</code><code class="n">request</code><code class="o">);</code>
<code class="n">Matcher</code> <code class="n">get</code> <code class="o">=</code> <code class="n">Pattern</code><code class="o">.</code><code class="na">compile</code><code class="o">(</code><code class="s">"GET /?(\\S*).*"</code><code class="o">).</code><code class="na">matcher</code><code class="o">(</code> <code class="n">request</code> <code class="o">);</code>
<code class="k">if</code> <code class="o">(</code> <code class="n">get</code><code class="o">.</code><code class="na">matches</code><code class="o">()</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">request</code> <code class="o">=</code> <code class="n">get</code><code class="o">.</code><code class="na">group</code><code class="o">(</code><code class="mi">1</code><code class="o">);</code>
<code class="k">if</code> <code class="o">(</code> <code class="n">request</code><code class="o">.</code><code class="na">endsWith</code><code class="o">(</code><code class="s">"/"</code><code class="o">)</code> <code class="o">||</code> <code class="n">request</code><code class="o">.</code><code class="na">equals</code><code class="o">(</code><code class="s">""</code><code class="o">)</code> <code class="o">)</code>
<code class="n">request</code> <code class="o">=</code> <code class="n">request</code> <code class="o">+</code> <code class="s">"index.html"</code><code class="o">;</code>
<code class="k">try</code> <code class="o">{</code>
<code class="n">FileInputStream</code> <code class="n">fis</code> <code class="o">=</code> <code class="k">new</code> <code class="n">FileInputStream</code> <code class="o">(</code> <code class="n">request</code> <code class="o">);</code>
<code class="kt">byte</code> <code class="o">[]</code> <code class="n">data</code> <code class="o">=</code> <code class="k">new</code> <code class="kt">byte</code> <code class="o">[</code> <code class="mi">64</code><code class="o">*</code><code class="mi">1024</code> <code class="o">];</code>
<code class="k">for</code><code class="o">(</code><code class="kt">int</code> <code class="n">read</code><code class="o">;</code> <code class="o">(</code><code class="n">read</code> <code class="o">=</code> <code class="n">fis</code><code class="o">.</code><code class="na">read</code><code class="o">(</code> <code class="n">data</code> <code class="o">))</code> <code class="o">></code> <code class="o">-</code><code class="mi">1</code><code class="o">;</code> <code class="o">)</code>
<code class="n">out</code><code class="o">.</code><code class="na">write</code><code class="o">(</code> <code class="n">data</code><code class="o">,</code> <code class="mi">0</code><code class="o">,</code> <code class="n">read</code> <code class="o">);</code>
<code class="n">out</code><code class="o">.</code><code class="na">flush</code><code class="o">();</code>
<code class="o">}</code> <code class="k">catch</code> <code class="o">(</code> <code class="n">FileNotFoundException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">pout</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="s">"404 Object Not Found"</code> <code class="o">);</code> <code class="o">}</code>
<code class="o">}</code> <code class="k">else</code>
<code class="n">pout</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="s">"400 Bad Request"</code> <code class="o">);</code>
<code class="n">client</code><code class="o">.</code><code class="na">close</code><code class="o">();</code>
<code class="o">}</code> <code class="k">catch</code> <code class="o">(</code> <code class="n">IOException</code> <code class="n">e</code> <code class="o">)</code> <code clas