📄 ch12.htm
字号:
<P>Both read routines must be changed so that there are no furtherread attempts once the entire length of bytes has been returned:<BLOCKQUOTE><TT>public int read() {<BR> <B>if ( count >= expected ) return-1; // add this line<BR></B> int c = super.read();<BR> if (c != -1) {<BR> justRead(1);<BR> }<BR> return c;<BR>}<BR>public int read(byte b[], int off, int len) {<BR><B> if ( count >= expected ) return-1;<BR><B> if ( count + len > expected ) len= expected - count; // add both of these</B></B></TT><FONT FACE="ZapfDingbats">Â</FONT><TT><B>lines<BR></FONT></B> int n= super.read(b, off, len);<BR> if (n != -1) {<BR> justRead(n);<BR> }<BR> return n;<BR>}</TT></BLOCKQUOTE><P>In addition, mark and reset operations must be intercepted sothe counts can be updated. As you can see from the previous listof public methods, these routines are absent, so add the followingtwo routines:<BLOCKQUOTE><TT>public synchronized void mark(int readlimit){<BR> meterMark = count;<BR> super.mark(readlimit);<BR> }<BR><BR> public synchronized void reset() {<BR> if ( meterMark!= -1 )<BR> count= meterMark;<BR> super.reset();<BR> }</TT></BLOCKQUOTE><P>The class variable <TT>meterMark</TT>also needs to be added to the class:<BLOCKQUOTE><TT>public<BR>class MeteredStream extends FilterInputStream<BR>{<BR> // Class variables.<BR> ...<BR> // Instance variables.<BR> ...<BR> <B>int meterMark = -1;</B> //add this line<BR> ...<BR>}</TT></BLOCKQUOTE><P>That's it! Recompile MeteredStream and move the class file intothe classes/net/www/html subdirectory.<H3><A NAME="CompilingUnderHotJava">Compiling Under HotJava</A></H3><P>Compiling under HotJava is the same as compiling under the JDK;the only difference is which version of javac you use. I prefernot to alter my path and environment for HotJava. Simply issuethe command specifying the full path to HotJava's version of javac:<BLOCKQUOTE><TT>c:\hotjava\bin\javac MeteredStream.java</TT></BLOCKQUOTE><P>Assuming you made the alterations correctly, this will createa MeteredStream.class file in the current directory. Rename theoriginal MeteredStream.class to MeteredStream.orig, then copyyour altered MeteredStream.class into its place. You have justchanged the source for HotJava! Now give it a try-run the serverfrom <A HREF="ch9.htm" >Chapters 9</A>, "Java Socket Programming,"10, "Native Methods and Java," or 11, "Buildinga Live Data Applet," and point your new HotJava at the server.The files transfer perfectly.<P>Before addressing content handlers, you need to add some enhancementsto the server.<H2><A NAME="TowardaMorePerfectServer"><FONT SIZE=5 COLOR=#FF0000>Towarda More Perfect Server</FONT></A></H2><P>The server used in Part IV, "Managing Live Data," wasuseful, but it lacked many features of an actual HTTP server.Specifically, there is no configuration file to map file extensionsto MIME content strings. In addition, some log information wouldbe helpful.<P>The first change is to the class name. Up to this point, the mainclass has been called BasicWebServer. Change this to HTTPServer,then perform a global search and replace to make the change. Nowthe configuration and logging methods can be added.<H3><A NAME="AddingaConfigurationFile">Adding a ConfigurationFile</A></H3><P>Since the server is an application, it is free to read and evenwrite the disk. The format of the configuration file is very straightforward:<UL><LI><FONT COLOR=#000000>port = #</FONT><LI><FONT COLOR=#000000>suffix = file_extension Content-type</FONT><LI><FONT COLOR=#000000>log = filename</FONT></UL><P>New methods are added to handle reading the configuration data.Listing 12.1 shows the new routines.<HR><BLOCKQUOTE><B>Listing 12.1. New routines for reading configuration files.<BR></B></BLOCKQUOTE><BLOCKQUOTE><TT> /**<BR> * Read the config file.<BR> */<BR> private void initialize()<BR> {<BR> String line =null;<BR> String configFile= "server.cfg";<BR><BR> // setup defaults<BR> HTTP_PORT = 80;<BR> suffix = new Hashtable();<BR><BR> try<BR> {<BR> FileInputStreaminFile = new FileInputStream(configFile);<BR> DataInputStreamis = new DataInputStream(inFile);<BR><BR> while((line = is.readLine()) != null)<BR> {<BR> StringTokenizericmd = new StringTokenizer(line, " \t=");<BR> addConfigEntry(icmd);<BR> }<BR> }<BR> catch (FileNotFoundExceptionfnf)<BR> {<BR> suffix.put("html","text/html");<BR> suffix.put("htm","text/html");<BR> suffix.put("class","text/plain");<BR> suffix.put("gif","image/gif");<BR> }<BR> catch (IOExceptionioe)<BR> {<BR> System.out.println("Errorreading config file: " + ioe);<BR> }<BR> }<BR><BR> /**<BR> * Add a config entry.<BR> * @param icmd contains the tokenizedline.<BR> */<BR> private void addConfigEntry(StringTokenizericmd)<BR> {<BR> if ( icmd.hasMoreTokens())<BR> {<BR> Stringparam = null;<BR> Stringcommand = icmd.nextToken();<BR> if( icmd.hasMoreTokens() )<BR> {<BR> param= icmd.nextToken();<BR> if( command.equalsIgnoreCase("PORT") )<BR> {<BR> HTTP_PORT= Integer.valueOf(param).intValue();<BR> if(debug)<BR> System.out.println("Monitoringport " + HTTP_PORT);<BR> }<BR> elseif ( command.equalsIgnoreCase("SUFFIX") )<BR> {<BR> if( icmd.hasMoreTokens() )<BR> {<BR> Stringparam2 = icmd.nextToken();<BR> suffix.put(param,param2);<BR> if(debug)<BR> {<BR> System.out.print(<BR> "Addingsuffix: '" + param + "'");<BR> System.out.println(" '"+ param2 + "'");<BR> }<BR> }<BR> }<BR> elseif ( command.equalsIgnoreCase("LOG") )<BR> {<BR> openLog(param);<BR> }<BR> else<BR> {<BR> System.out.print("Error:Unknown cfg entry: ");<BR> System.out.println(command);<BR> }<BR> }<BR> }<BR> }<BR><BR> /**<BR> * Open a log file<BR> * @param logfile contains the filenameto open<BR> */<BR> public void openLog(String logfile)<BR> {<BR> try<BR> {<BR> logFile= new PrintStream( new FileOutputStream(logfile) );<BR> logging= true;<BR> }<BR> catch (IOExceptionioe)<BR> {<BR> System.out.println("Erroropening log file: " + ioe);<BR> }<BR> }</TT></BLOCKQUOTE><HR><P>The StringTokenizer is instructed to parse equal sign charactersout of the stream. This allows the configuration file to omitthe equal sign and still function as expected. Only one configentry per line is allowed because <TT>readLine()</TT>is used to retrieve the entries.<P>File extension to MIME type mapping is contained in a hash tablecalled <TT>suffix</TT>. The file extensionis used as the key. If a configuration file contains multipleentries for an extension, only the last one will be stored. Hashtable <TT>put</TT> operations overwriteduplicate entries.<H3><A NAME="AddingStandardLogging">Adding Standard Logging</A></H3>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -