⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chapter15.html

📁 java 是一个很好的网络开发环境。由于它是通过解释的方法
💻 HTML
📖 第 1 页 / 共 5 页
字号:
just like opening files for reading and writing except that the
<B>InputStream</B> and <B>OutputStream</B> are created from the <B>Socket</B>
object. Both the <B>InputStream</B> and <B>OutputStream </B>objects are
converted to Java 1.1<A NAME="Index2627"></A>
<A NAME="Index2628"></A><A NAME="Index2629"></A><B>Reader </B>and
<A NAME="Index2630"></A><A NAME="Index2631"></A><B>Writer</B> objects using the
&#8220;converter&#8221; classes
<A NAME="Index2632"></A><A NAME="Index2633"></A><B>InputStreamReader</B> and
<A NAME="Index2634"></A><A NAME="Index2635"></A><B>OutputStreamWriter</B>,
respectively. You could also have used the Java 1.0<A NAME="Index2636"></A>
<A NAME="Index2637"></A><A NAME="Index2638"></A><B>InputStream</B> and
<A NAME="Index2639"></A><A NAME="Index2640"></A><B>OutputStream</B> classes
directly, but with output there&#8217;s a distinct advantage to using the
<B>Writer</B> approach. This appears with
<A NAME="Index2641"></A><A NAME="Index2642"></A><B>PrintWriter</B>, which has an
overloaded constructor that takes a second argument, a <B>boolean </B>flag that
indicates whether to automatically flush the output at the end of each
<B>println(&#160;)</B> (but <I>not </I><B>print(&#160;)</B>) statement. Every
time you write to <B>out</B>, its buffer must be flushed so the information goes
out over the network. Flushing is important for this particular example because
the client and server each wait for a line from the other party before
proceeding. If flushing doesn&#8217;t occur, the information will not be put
onto the network until the buffer is full, which causes lots of problems in this
example.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When writing network programs you
need to be careful about using automatic flushing. Every time you flush the
buffer a packet must be created and sent. In this case, that&#8217;s exactly
what we want, since if the packet containing the line isn&#8217;t sent then the
handshaking back and forth between server and client will stop. Put another way,
the end of a line is the end of a message. But in many cases messages
aren&#8217;t delimited by lines so it&#8217;s much more efficient to not use
auto flushing and instead let the built-in buffering decide when to build and
send a packet. This way, larger packets can be sent and the process will be
faster.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Note that, like virtually all
streams you open, these are buffered. There&#8217;s an exercise at the end of
the chapter to show you what happens if you don&#8217;t buffer the streams
(things get slow).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The infinite <B>while</B> loop
reads lines from the<B> BufferedReader in </B>and writes information to
<B>System.out</B> and to the <B>PrintWriter</B> <B>out</B>. Note that these
could be any streams, they just happen to be connected to the network.
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When the client sends the line
consisting of &#8220;END&#8221; the program breaks out of the loop and closes
the <B>Socket</B>. </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here&#8217;s the
client:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: JabberClient.java</font>
<font color=#009900>// Very simple client that just sends</font>
<font color=#009900>// lines to the server and reads lines</font>
<font color=#009900>// that the server sends.</font>
<font color=#0000ff>import</font> java.net.*;
<font color=#0000ff>import</font> java.io.*;

<font color=#0000ff>public</font> <font color=#0000ff>class</font> JabberClient {
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) 
      <font color=#0000ff>throws</font> IOException {
    <font color=#009900>// Passing null to getByName() produces the</font>
    <font color=#009900>// special "Local Loopback" IP address, for</font>
    <font color=#009900>// testing on one machine w/o a network:</font>
    InetAddress addr = 
      InetAddress.getByName(<font color=#0000ff>null</font>);
    <font color=#009900>// Alternatively, you can use </font>
    <font color=#009900>// the address or name:</font>
    <font color=#009900>// InetAddress addr = </font>
    <font color=#009900>//    InetAddress.getByName("127.0.0.1");</font>
    <font color=#009900>// InetAddress addr = </font>
    <font color=#009900>//    InetAddress.getByName("localhost");</font>
    System.out.println(<font color=#004488>"addr = "</font> + addr);
    Socket socket = 
      <font color=#0000ff>new</font> Socket(addr, JabberServer.PORT);
    <font color=#009900>// Guard everything in a try-finally to make</font>
    <font color=#009900>// sure that the socket is closed:</font>
    <font color=#0000ff>try</font> {
      System.out.println(<font color=#004488>"socket = "</font> + socket);
      BufferedReader in =
        <font color=#0000ff>new</font> BufferedReader(
          <font color=#0000ff>new</font> InputStreamReader(
            socket.getInputStream()));
      <font color=#009900>// Output is automatically flushed</font>
      <font color=#009900>// by PrintWriter:</font>
      PrintWriter out =
        <font color=#0000ff>new</font> PrintWriter(
          <font color=#0000ff>new</font> BufferedWriter(
            <font color=#0000ff>new</font> OutputStreamWriter(
              socket.getOutputStream())),<font color=#0000ff>true</font>);
      <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 10; i ++) {
        out.println(<font color=#004488>"howdy "</font> + i);
        String str = in.readLine();
        System.out.println(str);
      }
      out.println(<font color=#004488>"END"</font>);
    } <font color=#0000ff>finally</font> {
      System.out.println(<font color=#004488>"closing..."</font>);
      socket.close();
    }
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>main(&#160;)</B> you can see
all three ways to produce the <B>InetAddress</B> of the local loopback IP
address: using <B>null</B>, <B>localhost</B>, or the explicit reserved address
<B>127.0.0.1</B>. Of course, if you want to connect to a machine across a
network you substitute that machine&#8217;s IP address. When the <B>InetAddress
addr</B> is printed (via the automatic call to its <B>toString(&#160;)</B>
method) the result is:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>localhost/127.0.0.1</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">By handing <B>getByName(&#160;)</B>
a <B>null</B>, it defaulted to finding the <B>localhost</B>, and that produced
the special address <B>127.0.0.1</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Note that the
<A NAME="Index2643"></A><A NAME="Index2644"></A><B>Socket</B> called
<B>socket</B> is created with both the <B>InetAddress</B> and the port number.
To understand what it means when you print out one of these <B>Socket
</B>objects, remember that an Internet connection is determined uniquely by
these four pieces of data: <B>clientHost</B>, <B>clientPortNumber</B>,
<B>serverHost</B>, and <B>serverPortNumber</B>. When the server comes up, it
takes up its assigned port (8080) on the localhost (127.0.0.1). When the client
comes up, it is allocated to the next available port on its machine, 1077 in
this case, which also happens to be on the same machine (127.0.0.1) as the
server. Now, in order for data to move between the client and server, each side
has to know where to send it. Therefore, during the process of connecting to the
&#8220;known&#8221; server, the client sends a &#8220;return address&#8221; so
the server knows where to send its data. This is what you see in the example
output for the server side:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Socket[addr=127.0.0.1,port=1077,localport=8080]</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This means that the server just
accepted a connection from 127.0.0.1 on port 1077 while listening on its local
port (8080). On the client side:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Socket[addr=localhost/127.0.0.1,PORT=8080,localport=1077]</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">which means that the client made a
connection to 127.0.0.1 on port 8080 using the local port 1077.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You&#8217;ll notice that every time
you start up the client anew, the local port number is incremented. It starts at
1025 (one past the reserved block of ports) and keeps going up until you reboot
the machine, at which point it starts at 1025 again. (On UNIX machines, once the
upper limit of the socket range is reached, the numbers will wrap around to the
lowest available number again.)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Once the <B>Socket</B> object has
been created, the process of turning it into a <B>BufferedReader</B> and
<B>PrintWriter</B> is the same as in the server (again, in both cases you start
with a <B>Socket</B>). Here, the client initiates the conversation by sending
the string &#8220;howdy&#8221; followed by a number. Note that the buffer must
again be flushed (which happens automatically via the second argument to the
<B>PrintWriter </B>constructor). If the buffer isn&#8217;t flushed, the whole
conversation will hang because the initial &#8220;howdy&#8221; will never get
sent (the buffer isn&#8217;t full enough to cause the send to happen
automatically). Each line that is sent back from the server is written to
<B>System.out</B> to verify that everything is working correctly. To terminate
the conversation, the agreed-upon &#8220;END&#8221; is sent. If the client
simply hangs up, then the server throws an exception.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that the same care is
taken here to ensure that the network resources represented by the <B>Socket</B>
are properly cleaned up, using a <B>try-finally</B> block.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Sockets produce a
<A NAME="Index2645"></A>&#8220;dedicated&#8221; connection that persists until
it is explicitly disconnected. (The dedicated connection can still be
disconnected un-explicitly if one side, or an intermediary link, of the
connection crashes.) This means the two parties are locked in communication and
the connection is constantly open. This seems like a logical approach to
networking, but it puts an extra load on the network. Later in the chapter
you&#8217;ll see a different approach to networking, in which the connections
are only
temporary.</FONT><A NAME="_Toc375545497"></A><A NAME="_Toc408018770"></A><BR></P></DIV>
<A NAME="Heading517"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Serving multiple clients<BR><A NAME="Index2646"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>JabberServer</B> works, but
it can handle only one client at a time. In a typical server, you&#8217;ll want
to be able to deal with many clients at once. The answer is
<A NAME="Index2647"></A><A NAME="Index2648"></A>multithreading, and in languages
that don&#8217;t directly support multithreading this means all sorts of
complications. In Chapter 14 you saw that multithreading in Java is about as
simple as possible, considering that multithreading is a rather complex topic.
Because threading in Java is reasonably straightforward, making a server that
handles multiple clients is relatively easy.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The basic scheme is to make a
single <B>ServerSocket</B> in the server and call <B>accept(&#160;)</B> to wait
for a new connection. When <B>accept(&#160;)</B> returns, you take the resulting
<B>Socket</B> and use it to create a new thread whose job is to serve that
particular client. Then you call <B>accept(&#160;)</B> again to wait for a new
client.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In the following server code, you
can see that it looks similar to the <B>JabberServer.java</B> example except
that all of the operations to serve a particular client have been moved inside a
separate thread class:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: MultiJabberServer.java</font>
<font color=#009900>// A server that uses multithreading to handle </font>
<font color=#009900>// any number of clients.</font>
<font color=#0000ff>import</font> java.io.*;
<font color=#0000ff>import</font> java.net.*;

<font color=#0000ff>class</font> ServeOneJabber <font color=#0000ff>extends</font> Thread {
  <font color=#0000ff>private</font> Socket socket;
  <font color=#0000ff>private</font> BufferedReader in;
  <font color=#0000ff>private</font> PrintWriter out;
  <font color=#0000ff>public</font> ServeOneJabber(Socket s) 
      <font color=#0000ff>throws</font> IOException {
    socket = s;
    in = 
      <font color=#0000ff>new</font> BufferedReader(
        <font color=#0000ff>new</font> InputStreamReader(
          socket.getInputStream()));
    <font color=#009900>// Enable auto-flush:</font>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -