📄 tij0165.html
字号:
<html><body>
<table width="100%"><tr>
<td>
<a href="http://www.bruceeckel.com/javabook.html">Bruce Eckel's Thinking in Java</a>
</td>
<td align="right">
<a href="tij_c.html">Contents</a> | <a href="tij0164.html">Prev</a> | <a href="tij0166.html">Next</a>
</td>
</tr></table>
<hr>
<H2 ALIGN=LEFT>
Serving
multiple clients
<P><A NAME="Index2658"></A></H2>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>JabberServer</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
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="Index2659"></A><A NAME="Index2660"></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.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
basic scheme is to make a single
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ServerSocket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in the server and call
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>accept( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
to wait for a new connection. When
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>accept( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
returns, you take the resulting
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Socket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and use it to create a new thread whose job is to serve that particular client.
Then you call
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>accept( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
again to wait for a new client.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">In
the following server code, you can see that it looks similar to the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>JabberServer.java</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
example except that all of the operations to serve a particular client have
been moved inside a separate thread class:
</FONT><P></DIV>
<font color="#990000"><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>
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="#009900">// If any of the above calls throw an </font>
<font color="#009900">// exception, the caller is responsible for</font>
<font color="#009900">// closing the socket. Otherwise the thread</font>
<font color="#009900">// will close it.</font>
start(); <font color="#009900">// Calls run()</font>
}
<font color="#0000ff">public</font> <font color="#0000ff">void</font> run() {
<font color="#0000ff">try</font> {
<font color="#0000ff">while</font> (<font color="#0000ff">true</font>) {
String str = in.readLine();
<font color="#0000ff">if</font> (str.equals("END")) <font color="#0000ff">break</font>;
System.out.println("Echoing: " + str);
out.println(str);
}
System.out.println("closing...");
} <font color="#0000ff">catch</font> (IOException e) {
} <font color="#0000ff">finally</font> {
<font color="#0000ff">try</font> {
socket.close();
} <font color="#0000ff">catch</font>(IOException e) {}
}
}
}
<font color="#0000ff">public</font> <font color="#0000ff">class</font> MultiJabberServer {
<font color="#0000ff">static</font> <font color="#0000ff">final</font> <font color="#0000ff">int</font> PORT = 8080;
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args)
<font color="#0000ff">throws</font> IOException {
ServerSocket s = <font color="#0000ff">new</font> ServerSocket(PORT);
System.out.println("Server Started");
<font color="#0000ff">try</font> {
<font color="#0000ff">while</font>(<font color="#0000ff">true</font>) {
<font color="#009900">// Blocks until a connection occurs:</font>
Socket socket = s.accept();
<font color="#0000ff">try</font> {
<font color="#0000ff">new</font> ServeOneJabber(socket);
} <font color="#0000ff">catch</font>(IOException e) {
<font color="#009900">// If it fails, close the socket,</font>
<font color="#009900">// otherwise the thread will close it:</font>
socket.close();
}
}
} <font color="#0000ff">finally</font> {
s.close();
}
}
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ServeOneJabber
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">thread
takes the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Socket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object that’s produced by
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>accept( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>main( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
every time a new client makes a connection. Then, as before, it creates a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>BufferedReader</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and auto-flushed
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>PrintWriter</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object using the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Socket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
Finally, it calls the special
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Thread</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>start( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
which performs thread initialization and then calls
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>run( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
This performs the same kind of action as in the previous example: reading
something from the socket and then echoing it back until it reads the special
“END” signal.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
responsibility for cleaning up the socket must again be carefully designed. In
this case, the socket is created outside of the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ServeOneJabber</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
so the responsibility can be shared. If the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ServeOneJabber</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
constructor fails, it will just throw the exception to the caller, who will
then clean up the thread. But if the constructor succeeds, then the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ServeOneJabber</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object takes over responsibility for cleaning up the thread, in its
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>run( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Notice
the simplicity of the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>MultiJabberServer</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
As before, a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ServerSocket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is created and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>accept( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is called to allow a new connection. But this time, the return value of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>accept( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
(a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Socket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">)
is passed to the constructor for
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ServeOneJabber,</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
which creates a new thread to handle that connection. When the connection is
terminated, the thread simply goes away.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">If
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -