📄 chap15.htm
字号:
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 <B>in</B>
and <B>out</B> could be any streams, they just happen to be connected to the
network.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER15_I38'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER15_I39>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When the client sends the line consisting
of “END,” 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’s the client:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c15: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 < 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( )</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’s IP address. When the <B>InetAddress
addr</B> is printed (via the automatic call to its <B>toString( )</B>
method) the result is:
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER15_I39'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER15_I40>
</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( )</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>.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER15_I40'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER15_I41>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Note that the
<A NAME="Index2084"></A><A NAME="Index2085"></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 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 “known” server,
the client sends a “return address” 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:
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER15_I41'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER15_I42>
</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.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER15_I42'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER15_I43>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You’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.)
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER15_I43'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER15_I44>
</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 “howdy” 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’t flushed, the whole
conversation will hang because the initial “howdy” will never get
sent (the buffer isn’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 “END” is sent. If the client
simply hangs up, then the server throws an exception.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER15_I44'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER15_I45>
</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.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER15_I45'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER15_I46>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Sockets produce a
<A NAME="Index2086"></A>“dedicated” connection that persists until
it is explicitly disconnected. (The dedicated connection can still be
disconnected unexplicitly 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 this chapter
you’ll see a different approach to networking, in which the connections
are only temporary.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER15_I46'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER15_I47>
</FONT><A NAME="_Toc375545497"></A><A NAME="_Toc481064870"></A><BR></P></DIV>
<A NAME="Heading518"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Serving multiple clients<BR><A NAME="Index2087"></A></H3></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’ll want to be
able to deal with many clients at once. The answer is
<A NAME="Index2088"></A><A NAME="Index2089"></A>multithreading, and in languages
that don’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.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER15_I47'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER15_I48>
</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( )</B> to wait for a
new connection. When <B>accept( )</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( )</B> again to wait for a new
client.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER15_I48'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER15_I49>
</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>//: c15:MultiJabberServer.java</font>
<font color=#009900>// A server that uses multithreading </font>
<font color=#009900>// to handle 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>
out =
<font color=#0000ff>new</font> PrintWriter(
<font color=#0000ff>new</font> BufferedWriter(
<font color=#0000ff>new</font> OutputStreamWriter(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -