📄 29.html
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="description" content="Java,JDBC,EJB,Open Source,jdk,rmi">
<meta name="Keywords"
content="Java, servlets, Java servlet, Javascript, ActiveX, VRML,
applet, applets, directory, news, jdbc, applications,
Java applications, Java developer, Java development, developer,
classes, Jars.com, Jars, intranet, Java applet, Javabeans,
Java products, JDK, Java development kit, java development environment, JIT,
JavaPlan, enterprise tools, JVM, Java Virtual Machine, Java resources,
SUN, CGI, Perl, database, network, html,
xml, dhtml, rating, ratings, review, jars, cgi, programming,
software review, software rating">
<title>csdn_仅用一个类的服务器</title>
<style>
.news { BACKGROUND: #007cd3; font-family: "宋体"; font-size: 9pt }
.t { font-family: "宋体"; font-size: 9pt }
.t1 { color:#007cd3; font-family: "宋体"; font-size: 9pt }
.white { font-family: "宋体"; font-size: 9pt;color:#FFFFFF }
.red { font-family: "宋体"; font-size: 9pt;color:#FF0000 }
A:visited {color:#0000FF}
A:hover {color: #ff6666; text-decoration: none}
.text {font-size: 12px; line-height: 160%; font-family: "宋体"}
.text1 {color:#000000; font-size: 12px; line-height: 130%; font-family: "宋体"; text-decoration: none}
.text1:visited {color:#000000}
.text1:hover {color: #000000}
.text2 {color:#000000; font-size: 12px; line-height: 130%; font-family: "宋体"; text-decoration: none}
.text2:visited {color:#000000}
.text2:hover {color: #000000}
.text3 {font-size: 12px; line-height: 100%; font-family: "宋体"; text-decoration: none}
.large {font-size: 14.8px; line-height: 130%}
</style>
</head>
<body
<!--start first table -->
<tr>
<td WIDTH="100%" VALIGN="TOP">
<tr>
<td WIDTH="100%" CLASS="white"></td>
</tr>
<tr>
<td WIDTH="50%" bordercolor="#FFFFFF" CLASS="t1" bgcolor="#F0F0F0" align="center" nowrap>仅用一个类的服务器 </td>
<p> <td WIDTH="50%" bordercolor="#FFFFFF" CLASS="t1" bgcolor="#F0F0F0" align="center" nowrap>作者:Greg Travis </p>
</td>
</tr>
<tr>
<td WIDTH="100%" bordercolor="#FFFFFF" CLASS="t" bgcolor="#F0F0F0" colspan="2">
<!-- storybody -->
<p><i><让我们通过一个Java程序的例子,学习建立一个简单的TCP/IP服务器。大部分代码都放在一个类中,这样就很容易入门-></i></p>
<p>本文介绍了快速实现一个简单的TCP/IP服务器的技巧。核心代码都在单个类Server.java中,所以很容易建立和使用。</p>
<p>Server.java的结构很简单。它监听一个端口,对于每一个进来的连接,生成处理该连接的线程。实际处理该连接的子程序并没有实现,所以你必须自己扩展Server.java,写个子程序来实现。</p>
<p>(这样,从技术上讲,这就不是“仅用一个类的服务器”,因为你还需要用另外一个类,来完成某件事情。如果你真的坚持打算只用一个类,只需把子类中的代码放到Server.java中。)
</p>
<p>下面的EchoServer.java的代码体现了该程序的简单性。EchoServer 完成如下的简单功能:把客户发来的信息再发回去。</p>
<tr>
<td>
<pre><font face="Courier New" size="2">-----------------------------------------------
The One Class Server
-----------------------------------------------
EchoServer.java
-----------------------------------------------
-----------------------------------------------
import java.io.*;
import java.io.*;
public class EchoServer extends Server
{
// A single argument: the port on which to listen
public EchoServer( int port ) {
super( port );
}
// This function is called for each new connection; it
// implements whatever functionality is needed from the server.
// In this case, it simply sends back to the client all data
// that the client sends it. If it receives a 'q', the
// whole server is shut down.
public void process( InputStream in, OutputStream out ) {
try {
while (true) {
int c = in.read();
if (c=='q') {
close();
} else {
out.write( c );
}
}
} catch( IOException ie ) { System.out.println( ie ); }
}
// Command-line: "java EchoServer <port>"
static public void main( String args[] ) throws Exception {
int port = new Integer( args[0] ).intValue();
new EchoServer( port );
}
}</font></pre>
</td>
</tr>
<p>Server类的实现是很有趣的,因为它对于所有线程使用了一个Server类的实例。</p>
<!-- end of storybody -->
<!-- storybody -->
<h1 class="b2a">Listener 线程</h1>
<p>创建的第一个线程是“listener”线程。该线程中的代码对一个端口进行监听,等待进入的连接。一旦一个连接进入时,一个新的“connection”线程被创建,用于处理该连接。</p>
<p>Listener线程必须把用某种方法把新连接的Socket对象传送给新线程。因为Java在创建线程时,不具有传递参数的功能,所以使用了另外一个技术:哈希表。</p>
<p>一个哈希表对象可以把线程对象映射为Socket对象。listener 线程创建了一个新的线程,然后把该新线程和新的socket放到哈希表中。当新线程开始执行时,它从哈希表基于自己的线程对象中,通过调用Thread.currentThread(),读入socket。</p>
<p>对于Listener线程来说,因为它不需要其他线程“传递”什么信息,此时的哈希表中就没有Socket对象,这样,程序就可以判断这是一个listener
线程而不是一个connection线程。</p>
<p>下面为Listener线程的代码。现在的这个实现很简单,因为它省略了一些处理。尤其是发生例外时的处理,我没有编写这些代码。因为这需要做更多的工作,而且依赖于具体的应用。</p>
<tr>
<td>
<pre><font face="Courier New" size="2">-----------------------------------------------
The One Class Server
-----------------------------------------------
The Listener Thread
-----------------------------------------------
-----------------------------------------------
import java.io.*;
import java.net.*;
import java.util.*;
abstract public class Server implements Runnable
{
// The port the server will listen on
private int port;
// Used to "pass" a Socket to the new thread that will process it
private Hashtable handoff = new Hashtable();
// The first thread -- we store it here so we can kill it
// first when closing.
private Thread listener;
// A list of the Threads that have been started
private Vector threads = new Vector();
// A list of the Sockets that have connected to us
private Vector sockets = new Vector();
// The listen socket
private ServerSocket ss;
public Server( int port ) {
this.port = port;
// Start the listener thread. Because we haven't passed a Socket
// object to this thread in the handoff table, it will know
// that it is to be the listener thread.
listener = new Thread( this );
listener.start();
}
synchronized public void close() {
// First, make sure there aren't any incoming connections
listener.stop();
// Now, close all the sockets
for (Enumeration e = sockets.elements(); e.hasMoreElements();){
Socket s = (Socket)e.nextElement();
try {
s.close();
} catch( IOException ie ) { System.out.println( ie );}
}
// And stop all the threads
for (Enumeration e = threads.elements(); e.hasMoreElements();){
Thread t = (Thread)e.nextElement();
// But let's not stop *ourselves* yet!
if (t != Thread.currentThread())
t.stop();
}
System.out.println( "Shutting down!" );
// Now we can stop ourselves.
Thread.currentThread().stop();
}
// This routine does the actual work of the server. It's not
// implemented, so you have to extend this class to actually get
// something done.
abstract public void process( InputStream in, OutputStream out );
// This routine processes all the connections. All the threads
// started by this class run this same routine of the same instance
// of Server.
public void run() {
// Get the Socket that is being "passed" to us by the listener
// thread. If there is no Socket here for us, then we ARE the
// listener thread, or at least we are about to be.
Socket s = (Socket)handoff.get( Thread.currentThread() );
if (s==null) {
// Aha -- we are the very first thread, the listener thread.
// Start listening.
try {
// Set up the listen socket.
ss = new ServerSocket( port );
System.out.println( "Listening on "+port );
while (true) {
// Accept a new connection
s = ss.accept();
synchronized( this ) {
System.out.println( "Connection from "+s.getInetAddress() );
// Make a new thread to handle this connection
Thread t = new Thread( this );
// Store the thread and socket in the lists
sockets.addElement( s );
threads.addElement( t );
// The Socket object is "passed" to the new thread by
// getting stuffed here. When the new thread is started,
// it will pull the Socket object out of here based on
// its own Thread object.
handoff.put( t, s );
// All set! Start the thread!
t.start();
}
}
} catch( IOException ie ) {}
} else {
// We are a processing socket.
try {
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
// Call the actually-do-something routine in the subclass of
// this object, so that something can actually get done.
process( in, out );
} catch( IOException ie ) { System.out.println( ie ); }
}
}
}</font>
</pre>
</td>
</tr>
<p>此处,我们也没有对socket,线程列表以及对handoff哈希表进行整理,大家可以修改这个类,以便能够完善这些工作,我把它们的代码编写工作作为练习,留给读者。</p>
<!-- end of storybody -->
</td>
</tr>
</td>
</tr>
</div>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -