23----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方upcaseNext=ch=='-';}returnnewString(chars);}publicStringget(Stringkey){return(String)super.get(fix(key));}publicvoidput(Stringkey,Stringval){super.put(fix(key),val);}}HttpResponse.javaHttpResponse类是所有与HTTP服务器应答有关的事物的包装程序。它被httpd类的代理部分使用。当你向一个HTTP服务器发送一个请求时,它以一个存储在statusCode中的整数形式的代码以及一个存储在reasonPhrase中的文本应答(这些变量名在正式的HTTP规范中规定)。这个单行的响应后面跟随着一个包含进一步应答信息的MIME头。我们用以前解释过的MimeHeader对象来解析这个字符串。MimeHeader对象存储在HttpResponse类的mh变量中。这些变量不是私有的,所以httpd可以直接使用它们。构造函数如果用一个字符串参数创建一个HttpResponse类对象,它被用来作为一个HTTP服务器的原始响应,并传向下面描述的parse( )来初始化对象。你还可以传入一个预计算的状态码,原因语句以及MIME标头。parse( )parse( )方法获得从HTTP服务器上读取的原始数据,从第一行解析出statusCode和reasonPhrase,然后在剩下的行外部创建一个MimeHeader。toString( )toString( )方法是parse( )的逆方法。它获取HttpResponse对象的当前值并返回一个字符串,HTTP客户希望从服务器读回该字符串。代码下面是HttpResponse的源代码:importjava.io.*;/**HttpResponse*ParseareturnmessageandMIMEheaderfromaserver.*HTTP/1.0302Found=redirection,checkLocationforwhere.*HTTP/1.0200OK=filedatacomesaftermimeheader.*/classHttpResponse{intstatusCode;//Status-CodeinspecStringreasonPhrase;//Reason-PhraseinspecMimeHeadermh;staticStringCRLF="\r
24";voidparse(Stringrequest){intfsp=request.indexOf('');
25----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方intnsp=request.indexOf('',fsp+1);inteol=request.indexOf('
26');Stringprotocol=request.substring(0,fsp);statusCode=Integer.parseInt(request.substring(fsp+1,nsp));reasonPhrase=request.substring(nsp+1,eol);Stringraw_mime_header=request.substring(eol+1);mh=newMimeHeader(raw_mime_header);}HttpResponse(Stringrequest){parse(request);}HttpResponse(intcode,Stringreason,MimeHeaderm){statusCode=code;reasonPhrase=reason;mh=m;}publicStringtoString(){return"HTTP/1.0"+statusCode+""+reasonPhrase+CRLF+mh+CRLF;}}UrlCacheEntry.java为在服务器上保存文档的内容,必须在用于找回文档的URL和文档自身描述之间建立联系。一个文档由它的MimeHeader和原始数据描述。例如一副图像可以被一个Content-Type:image/gif样式的MimeHeader描述,而原始图像数据就是一个字节数组。同样,一个网页在它的MimeHeader中有Content-Type:text/html关键字/值对,而原始数据就是HTML页的内容。再次申明,实例变量不是私有的,所以httpd可以自由的访问它们。构造函数UrlCacheEntry对象的构造函数需要用URL作为关键字以及一个与之相关的MimeHeader。如果MimeHeader内部有一个名为Content-Length成员(大多数情况下如此),数据区域被预先分配足够大的空间来保存它的内容。append( )append( )方法用来给UrlCacheEntry对象增添数据的。它不是一个简单的setData( )方法,原因是数据可能流经网络且需要在一定时间被存储成块。append( )方法处理三种情形。第一种,数据缓冲区根本没有分配。第二种情形,数据缓冲区对于引入的数据来说太小,所以它被重新分配。最后一种情况,引入的数据正好可以插入缓冲区。在任何时候,length成员变量保存数据缓冲区当前的有效大小值。代码下面是UrlCacheEntry的源代码:classUrlCacheEntry{Stringurl;MimeHeadermh;bytedata[];intlength=
27----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方0;publicUrlCacheEntry(Stringu,MimeHeaderm){url=u;mh=m;Stringcl=mh.get("Content-Length");if(cl!=null){data=newbyte[Integer.parseInt(cl)];}}voidappend(byted[],intn){if(data==null){data=newbyte[n];System.arraycopy(d,0,data,0,n);length=n;}elseif(length+n>data.length){byteold[]=data;data=newbyte[old.length+n];System.arraycopy(old,0,data,0,old.length);System.arraycopy(d,0,data,old.length,n);}else{System.arraycopy(d,0,data,length,n);length+=n;}}}LogMessage.javaLogMessage是一个简单的接口,它只定义了一个方法log( ),该方法只有一个String型参数。它用来抽象从httpd获得消息的输出。在应用程序条件下,该方法用来打印标准应用程序起始处控制台的输出。在小应用程序情况下,数据被送到一个视窗文本缓冲区。代码下面是LogMessage的源程序:interfaceLogMessage{publicvoidlog(Stringmsg);}httpd.java这真是一个具有很多功能的大类。我们将一个方法一个方法的讲解它。构造函数存在5个主要的实例变量:port,docRoot,log,cache和stopFlag,它们都是私有的。其中的三个可以由httpd的独立构造函数设置,显示如下:httpd(intp,Stringdr,LogMessagelm)它初始化监听端口,初始化检索文件的目录以及初始化发送消息的接口。第四个实例变量cache,是在RAM中保存所有文件的Hashtable,它是在对象创建时被初始化的。stopFlag控制程序的执行。
28----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方静态部分该类中有几个重要的静态变量。MIME标头中的“Server”域报告的版本在变量version中被发现。接着定义了一些常量:HTML文件的MIME类型,mime_text_html;MIME的结束顺序,CRLF;代替原始目录请求返回的HTML文件名,indexfile以及在输入/输出中用到的数据缓冲区的大小,buffer_size。然后mt定义了一系列文件扩展名和这些文件相应的MIME类型。typesHashtable在下一个块中被静态初始化,以用来包含作为可选关键字和值的数组mt。接着可以用fnameToMimeType( )方法来返回传入的每个filename的合适的MIME类型。如果filename不含mt表中的任何一个扩展名,该方法返回defaultExt或“text/plain.”。统计计算器下面,我们声明另外5个实例变量。它们是没有private修饰符,所以一个外部监控器可以检查这些值并以图形形式显示它们(我们将在后面演示)。这些变量表示了我们的Web服务器所用的统计资料。点击数和提供的字节的原始数目被存储在hits_served和bytes_served中。通常存储在高速缓存中的文件和字节数被存放在files_in_cache和bytes_in_cache中。最后,我们把成功在高速缓存外部提供服务的点击数目存放在hits_to_cache中。toBytes( )接着,我们有一个方便的程序,toBytes( )。该程序把它的字符串转变成一个字节数组。这是十分必要的,因为Java的String对象是以统一编码的字符形式存储的,而Internet协议中的混合语例如HTTP是老式的8位ASCII码。makeMimeHeader( )MakeMimeHeader()方法是另一个方便的方法,它用来创建由一些关键字值填充的MimeHeader对象。该方法返回的MimeHeader在Date成员中含有当前时间和时期,在Server成员中有服务器的名称和版本,Content-Type成员中有type参数,Content-Length成员中有length参数。error( )error( )方法用来格式化HTML页并返回提出不能完成请求的Web客户。第一个参数code,是返回的出错代码。一般它在400到499之间。我们的服务器返回404和405错误。它用HttpResponse类和适当的MimeHeader来封装返回的代码。该方法返回字符串表示是与HTML页有关的响应。该页包括易于人读的错误代码信息msg和导致错误的url请求。getRawRequest( )GetRawRequest()方法是很简单的。它从流读取数据直到它获得两个连续的换行符。它忽略回车符号并且只寻找换行符。一旦它已经发现了连续的两个换行符,它使字节数组转向一个String对象并返回该对象。如果输入流在结束之前没有生成两个连续的换行符,它将返回null。这说明了HTTP服务器和客户的消息是怎样被格式化的。它们以状态的一行开始然后立即跟着一个MIME头。MIME头的结尾被两个换行符从剩余的内容中分离。logEntry( )logEntry( )方法用来报告标准格式下的HTTP服务器的每个点击数。该方法生成的格式也许看起来有一点奇怪,但是它和HTTP日志文件的当前标准相匹配。该方法有若干个用来格式化每个日志项的日期戳的辅助变量和方法。months数组用来把月份转换成字符串。当host变量接受一个给定主机的连接时它由主HTTP循环设置。fmt02d( )方法把0到9的整数格式化成两位的,第一位为零的数,然后结果字符串通过LogMessage接口变量log传输。
29----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方writeString( )另一个方便的方法writeString( ),用来隐藏字符到字节数组的转变,以使它可以被写入流。writeUCE( )writeUCE( )方法占取一个OutputStream和一个UrlCacheEntry。它从高速缓存项提取信息,以便给网络客户传送消息。消息中包含适当的响应代码,MIME标头和内容。serveFromCache( )这个布尔方法试图在高速缓存中发现一个特殊的URL。如果成功,缓存项的内容被写给客户,hits_to_cache变量递增,调用者被返回true。否则,它只返回false。loadFile( )该方法占用了一个InputStream、与之相应的url以及该URL的MimeHeader。用存储在MimeHeader的信息创建一个新的UrlCacheEntry。输入流在buffer_size字节块中被读取并传入UrlCacheEntry。结果的UrlCacheEntry存储在高速缓存中。files_in_cache和bytes_in_cache变量更新,UrlCacheEntry返回调用者。readFile( )readFile( )方法就loadFile( )方法来说看起来有些多余,实际不然。该方法严格的从本地文件系统读取文件。在本地文件系统中,loadFile( )方法用来与各种类型的流交流。如果File对象f存在,将会为它创建一个InputStream类。文件的大小是决定了的,MIME类型来自文件名。当loadFile( )被调用来做实际的读取和缓存高速工作时,有两个变量用来创建合适的MimeHeader。writeDiskCache( )writeDiskCache( )方法占用一个UrlCacheEntry对象并且把它持久的写入本地磁盘。它从URL中建立一个目录名,确保用与系统有关的separatorChar代替斜线(/)字符。然后它调用mkdirs( )方法来保证这个URL的本地磁盘路径存在。最后,它打开一个FileOutputStream,向它写入所有的数据然后关闭它。handleProxy( )HandleProxy()程序是该服务器的两个主要模式之一。基础思想是:如果你把你的浏览器设置成把该服务器当成代理服务器,则要传给它的请求将包括完整的URL,URL中常规GET方法可删除“http://”和主机名部分。我们仅把完整的URL拆碎,寻找“://”序列,其次是斜线(/),然后是使用非标准端口号的服务器的另一个冒号(:)。一旦我们发现了这些字符,我们就可以知道已经所需要的主机和端口号以及我们需要获取的URL。然后我们可以试图从RAM高速缓存中转载一个先前保存过的文档版本。如果失败,我们可以试图从文件系统装载它到RAM高速缓存并且再尝试从RAM高速缓存装载它。如果此举失败,那么事情变得很有趣,因为我们必须从远程站点读取该文件。为此,我们打开一个远程站点和端口的套接字。我们发送一个GET请求,要求传给我们的URL。无论我们从远程站点获得什么响应标头信息,我们把它传给客户。如果代码是200,对于成功的文件传输,我们还把确认数据流读到一个新的UrlCacheEntry类并且把它写入客户套接字。然后,我们调用writeDiskCache( )来保存传输结果到本地磁盘。我们记录传输日志,关闭套接字,然后返回。handleGet( )当http后台进程像一个普通的Web服务器一样工作时,handleGet( )被调用。它有一个服务于文件的本地磁盘文件根目录。handleGet( )的参数告诉它向何处写结果,何处访问URL以及何处请求网络浏览器的MimeHeader
30----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方。这个MIME标头将包括用户代理字符串和其他有用的属性。开始,我们试图在RAM高速缓存外为URL提供服务。如果此举失败,为寻找URL,我们顺序访问文件系统。如果文件不存在或不可读,我们向Web客户报告一个错误。否则,我们就用readFile( )方法获得文件的内容并把它们输入到高速缓存。然后调用writeUCE( )方法以用来传输文件内容到客户套接字。doRequest( )每次连接服务器时都会调用一次doRequest( )方法。它解析请求字符串和引入的MIME标头。它在请求字符串中是否存在“://”的基础上判定是调用handleProxy( )还是handleGet( )方法。如果不用GET,而使用任何其他的方法例如HEAD或POST,该程序向客户返回一个405错误。注意如果stopFlag是true时HTTP请求被忽略。run( )run( )方法在服务器线程启动时被调用。它在指定端口生成一个新的ServerSocket,在服务器套接字处进入一个调用accept( )的无限循环,把结果Socket传给doRequest( )作检查。start( )ANDstop( )存在两个用来启动和终止服务器过程的方法。这些方法设置stopFlag的值。main( )你可以在命令行用main( )方法来运行应用程序。它为服务器自身设置LogMessage参数,然后为log( )提供简单的控制台输出执行。代码下面是httpd的源代码:importjava.net.*;importjava.io.*;importjava.text.*;importjava.util.*;classhttpdimplementsRunnable,LogMessage{privateintport;privateStringdocRoot;privateLogMessagelog;privateHashtablecache=newHashtable();privatebooleanstopFlag;privatestaticStringversion="1.0";privatestaticStringmime_text_html="text/html";privatestaticStringCRLF="\r
31";privatestaticStringindexfile="index.html";privatestaticintbuffer_size=8192;staticStringmt[]={//mappingfromfileexttoMime-Type"txt","text/plain","html",mime_text_html,"htm","text/html","gif","image/gif","jpg","image/jpg","jpeg","image/jpg","class","application/octet-stream"};staticStringdefaultExt="txt";staticHashtabletypes=newHashtable();static{for(inti=0;i32----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方}staticStringfnameToMimeType(Stringfilename){if(filename.endsWith("/"))//specialforindexfiles.returnmime_text_html;intdot=filename.lastIndexOf('.');Stringext=(dot>0)?filename.substring(dot+1):defaultExt;Stringret=(String)types.get(ext);returnret!=null?ret:(String)types.get(defaultExt);}inthits_served=0;intbytes_served=0;intfiles_in_cache=0;intbytes_in_cache=0;inthits_to_cache=0;privatefinalbytetoBytes(Strings)[]{byteb[]=s.getBytes();returnb;}privateMimeHeadermakeMimeHeader(Stringtype,intlength){MimeHeadermh=newMimeHeader();DatecurDate=newDate();TimeZonegmtTz=TimeZone.getTimeZone("GMT");SimpleDateFormatsdf=newSimpleDateFormat("ddMMMyyyyhh:mm:sszzz");sdf.setTimeZone(gmtTz);mh.put("Date",sdf.format(curDate));mh.put("Server","JavaCompleteReference/"+version);mh.put("Content-Type",type);if(length>=0)mh.put("Content-Length",String.valueOf(length));returnmh;}privateStringerror(intcode,Stringmsg,Stringurl){Stringhtml_page="
"+CRLF+""+code+""+msg+"
"+CRLF;if(url!=null)html_page+="ErrorwhenfetchingURL:"+url+CRLF;html_page+=""+CRLF;MimeHeadermh=makeMimeHeader(mime_text_html,html_page.length());HttpResponsehr=newHttpResponse(code,msg,mh);logEntry("GET",url,code,0);returnhr+html_page;}//Read'in'untilyougettwo
33'sinarow.//ReturnuptothatpointasaString.//Discardall\r's.
34----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方privateStringgetRawRequest(InputStreamin)throwsIOException{bytebuf[]=newbyte[buffer_size];intpos=0;intc;while((c=in.read())!=-1){switch(c){case'\r':break;case'
35':if(buf[pos-1]==c){returnnewString(buf,0,pos);}default:buf[pos++]=(byte)c;}}returnnull;}staticStringmonths[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};privateStringhost;//fmt02disthesameasC'sprintf("%02d",i)privatefinalStringfmt02d(inti){if(i<0){i=-i;return((i<9)?"-0":"-")+i;}else{return((i<9)?"0":"")+i;}}privatevoidlogEntry(Stringcmd,Stringurl,intcode,intsize){Calendarcalendar=Calendar.getInstance();inttzmin=calendar.get(Calendar.ZONE_OFFSET)/(60*1000);inttzhour=tzmin/60;tzmin-=tzhour*60;log.log(host+"--["+fmt02d(calendar.get(Calendar.DATE))+"/"+months[calendar.get(Calendar.MONTH)]+"/"+calendar.get(Calendar.YEAR)+":"+fmt02d(calendar.get(Calendar.HOUR))+":"+fmt02d(calendar.get(Calendar.MINUTE))+":"+fmt02d(calendar.get(Calendar.SECOND))+""+fmt02d(tzhour)+fmt02d(tzmin)+"]\""+cmd+""+url+"HTTP/1.0\""+code+""+size+"
36");
37----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方hits_served++;bytes_served+=size;}privatevoidwriteString(OutputStreamout,Strings)throwsIOException{out.write(toBytes(s));}privatevoidwriteUCE(OutputStreamout,UrlCacheEntryuce)throwsIOException{HttpResponsehr=newHttpResponse(200,"OK",uce.mh);writeString(out,hr.toString());out.write(uce.data,0,uce.length);logEntry("GET",uce.url,200,uce.length);}privatebooleanserveFromCache(OutputStreamout,Stringurl)throwsIOException{UrlCacheEntryuce;if((uce=(UrlCacheEntry)cache.get(url))!=null){writeUCE(out,uce);hits_to_cache++;returntrue;}returnfalse;}privateUrlCacheEntryloadFile(InputStreamin,Stringurl,MimeHeadermh)throwsIOException{UrlCacheEntryuce;bytefile_buf[]=newbyte[buffer_size];uce=newUrlCacheEntry(url,mh);intsize=0;intn;while((n=in.read(file_buf))>=0){uce.append(file_buf,n);size+=n;}in.close();cache.put(url,uce);files_in_cache++;bytes_in_cache+=uce.length;returnuce;}privateUrlCacheEntryreadFile(Filef,Stringurl)throwsIOException{if(!f.exists())returnnull;
38----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方InputStreamin=newFileInputStream(f);intfile_length=in.available();Stringmime_type=fnameToMimeType(url);MimeHeadermh=makeMimeHeader(mime_type,file_length);UrlCacheEntryuce=loadFile(in,url,mh);returnuce;}privatevoidwriteDiskCache(UrlCacheEntryuce)throwsIOException{Stringpath=docRoot+uce.url;Stringdir=path.substring(0,path.lastIndexOf("/"));dir.replace('/',File.separatorChar);newFile(dir).mkdirs();FileOutputStreamout=newFileOutputStream(path);out.write(uce.data,0,uce.length);out.close();}//Aclientasksusforaurlthatlookslikethis://http://the.internet.site/the/url//wegogetitfromthesiteandreturnit...privatevoidhandleProxy(OutputStreamout,Stringurl,MimeHeaderinmh){try{intstart=url.indexOf("://")+3;intpath=url.indexOf('/',start);Stringsite=url.substring(start,path).toLowerCase();intport=80;Stringserver_url=url.substring(path);intcolon=site.indexOf(':');if(colon>0){port=Integer.parseInt(site.substring(colon+1));site=site.substring(0,colon);}url="/cache/"+site+((port!=80)?(":"+port):"")+server_url;if(url.endsWith("/"))url+=indexfile;if(!serveFromCache(out,url)){if(readFile(newFile(docRoot+url),url)!=null){serveFromCache(out,url);return;}//Ifwehaven'talreadycachedthispage,openasocket//tothesite'sportandsendaGETcommandtoit.//Wemodifytheuser-agenttoaddourselves..."via".Socketserver=newSocket(site,port);InputStreamserver_in=server.getInputStream();
39----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方OutputStreamserver_out=server.getOutputStream();inmh.put("User-Agent",inmh.get("User-Agent")+"viaJavaCompleteReferenceProxy/"+version);Stringreq="GET"+server_url+"HTTP/1.0"+CRLF+inmh+CRLF;writeString(server_out,req);Stringraw_request=getRawRequest(server_in);HttpResponseserver_response=newHttpResponse(raw_request);writeString(out,server_response.toString());if(server_response.statusCode==200){UrlCacheEntryuce=loadFile(server_in,url,server_response.mh);out.write(uce.data,0,uce.length);writeDiskCache(uce);logEntry("GET",site+server_url,200,uce.length);}server_out.close();server.close();}}catch(IOExceptione){log.log("Exception:"+e);}}privatevoidhandleGet(OutputStreamout,Stringurl,MimeHeaderinmh){bytefile_buf[]=newbyte[buffer_size];Stringfilename=docRoot+url+(url.endsWith("/")?indexfile:"");try{if(!serveFromCache(out,url)){Filef=newFile(filename);if(!f.exists()){writeString(out,error(404,"NotFound",filename));return;}if(!f.canRead()){writeString(out,error(404,"PermissionDenied",filename));return;}UrlCacheEntryuce=readFile(f,url);writeUCE(out,uce);}}catch(IOExceptione){log.log("Exception:"+e);}}privatevoiddoRequest(Sockets)throwsIOException{if(stopFlag)return;InputStreamin=s.getInputStream();
40----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方OutputStreamout=s.getOutputStream();Stringrequest=getRawRequest(in);intfsp=request.indexOf('');intnsp=request.indexOf('',fsp+1);inteol=request.indexOf('
41');Stringmethod=request.substring(0,fsp);Stringurl=request.substring(fsp+1,nsp);Stringraw_mime_header=request.substring(eol+1);MimeHeaderinmh=newMimeHeader(raw_mime_header);request=request.substring(0,eol);if(method.equalsIgnoreCase("get")){if(url.indexOf("://")>=0){handleProxy(out,url,inmh);}else{handleGet(out,url,inmh);}}else{writeString(out,error(405,"MethodNotAllowed",method));}in.close();out.close();}publicvoidrun(){try{ServerSocketacceptSocket;acceptSocket=newServerSocket(port);while(true){Sockets=acceptSocket.accept();host=s.getInetAddress().getHostName();doRequest(s);s.close();}}catch(IOExceptione){log.log("acceptloopIOException:"+e+"
42");}catch(Exceptione){log.log("Exception:"+e);}}privateThreadt;publicsynchronizedvoidstart(){stopFlag=false;if(t==null){t=newThread(this);t.start();}}publicsynchronizedvoidstop(){
43----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方stopFlag=true;log.log("Stoppedat"+newDate()+"
44");}publichttpd(intp,Stringdr,LogMessagelm){port=p;docRoot=dr;log=lm;}//Thismainandlogmethodallowhttpdtoberunfromtheconsole.publicstaticvoidmain(Stringargs[]){httpdh=newhttpd(80,"c:\\www",null);h.log=h;h.start();try{Thread.currentThread().join();}catch(InterruptedExceptione){};}publicvoidlog(Stringm){System.out.print(m);}}HTTP.java这里是一个给HTTP服务器一个“前面板”功能的applet类。该applet有两个可以用来配置服务器的参数:port和docroot。这是一个很简单的小应用程序。它创建了一个httpd实例,把它作为LogMessage接口传入自己。然后创建了两个面板。一个面板在顶部有一个简单的标签,在中部是一个TextArea文本区以显示LogMessage;另一个面板在底部有两个按钮及一个标签。小应用程序的start( )和stop( )方法调用httpd相应的方法。标注有“Start”和“Stop”的按钮调用httpd中它们相应的方法。在任何时候只要一条消息被记录,右下角的Label对象就更新,这样它包含httpd最新的统计数据。importjava.util.*;importjava.applet.*;importjava.awt.*;importjava.awt.event.*;publicclassHTTPextendsAppletimplementsLogMessage,ActionListener{privateintm_port=80;privateStringm_docroot="c:\\www";privatehttpdm_httpd;privateTextAream_log;privateLabelstatus;privatefinalStringPARAM_port="port";privatefinalStringPARAM_docroot="docroot";
45----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方publicHTTP(){}publicvoidinit(){setBackground(Color.white);Stringparam;//port:Portnumbertolistenonparam=getParameter(PARAM_port);if(param!=null)m_port=Integer.parseInt(param);//docroot:webdocumentrootparam=getParameter(PARAM_docroot);if(param!=null)m_docroot=param;setLayout(newBorderLayout());Labellab=newLabel("JavaHTTPD");lab.setFont(newFont("SansSerif",Font.BOLD,18));add("North",lab);m_log=newTextArea("",24,80);add("Center",m_log);Panelp=newPanel();p.setLayout(newFlowLayout(FlowLayout.CENTER,1,1));add("South",p);Buttonbstart=newButton("Start");bstart.addActionListener(this);p.add(bstart);Buttonbstop=newButton("Stop");bstop.addActionListener(this);p.add(bstop);status=newLabel("raw");status.setForeground(Color.green);status.setFont(newFont("SansSerif",Font.BOLD,10));p.add(status);m_httpd=newhttpd(m_port,m_docroot,this);}publicvoiddestroy(){stop();}publicvoidpaint(Graphicsg){}publicvoidstart(){m_httpd.start();status.setText("Running");clear_log("Logstartedon"+newDate()+"
46");
47----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方}publicvoidstop(){m_httpd.stop();status.setText("Stopped");}publicvoidactionPerformed(ActionEventae){Stringlabel=ae.getActionCommand();if(label.equals("Start")){start();}else{stop();}}publicvoidclear_log(Stringmsg){m_log.setText(msg+"
48");}publicvoidlog(Stringmsg){m_log.append(msg);status.setText(m_httpd.hits_served+"hits("+(m_httpd.bytes_served/1024)+"K),"+m_httpd.files_in_cache+"cachedfiles("+(m_httpd.bytes_in_cache/1024)+"K),"+m_httpd.hits_to_cache+"cachedhits");status.setSize(status.getPreferredSize());}}注意:httpd.java和HTTP.java文件中,代码是在假定文件根部是“c:\www”的基础上建立的。你可能需要改变配置的值。因为这个小应用程序写入一个日志文件,它只能在被信任的条件下工作。例如,一个小应用程序在它可以获得用户CLASSPATH时被信任。18.9数据报对于你的大多数网络需求,你会对TCP/IP型网络很满意。它提供了有序的、可预测和可靠的信息包数据流。但是,这样做的代价也很大。TCP包含很多在拥挤的网络中处理拥塞控制的复杂算法以及信息丢失的悲观的预测。这导致了一个效率很差的传输数据方式。数据报是一种可选的替换方法。数据报(Datagrams)是在机器间传递的信息包,它有些像从一个训练有素但是很盲目的捕手投出一记有力的传球给三垒。一旦数据报被释放给它们预定的目标,不保证它们一定到达目的地,甚至不保证一定存在数据的接收者。同样,数据报被接受时,不保证它在传输过程不受损坏,不保证发送它的机器仍在那儿等待响应。Java通过两个类实现UDP协议顶层的数据报:DatagramPacket对象是数据容器,
49----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方DatagramSocket是用来发送和接受DatagramPackets的机制。18.9.1DatagramPacketDatagramPackets可以用四个构造函数中的一个创建。第一个构造函数指定了一个接收数据的缓冲区和信息包的容量大小。它通过DatagramSocket接收数据。第二种形式允许你在存储数据的缓冲区中指定一个偏移量。第三种形式指定了一个用于DatagramSocket决定信息包将被送往何处的目标地址和端口。第四种形式从数据中指定的偏移量位置开始传输数据包。想象前两种形式是建立在“盒内”的,后两种形式形成了填塞物,并为一个信封注明了地址。下面是四个构造函数:DatagramPacket(bytedata[],intsize)DatagramPacket(bytedata[],intoffset,intsize)DatagramPacket(bytedata[],intsize,InetAddressipAddress,intport)DatagramPacket(bytedata[],intoffset,intsize,InetAddressipAddress,intport)存在几种方法可获取DatagramPacket内部状态。它们对信息包的目标地址和端口号以及原始数据和数据长度有完全的使用权,下面是它们的概述:InetAddressgetAddress( )返回目标文件InetAddress,一般用于发送。IntgetPort( )返回端口号。byte[]getData( )返回包含在数据包中的字节数组数据。多用于在接收数据之后从数据包来检索数据。IntgetLength( )返回包含在将从getData( )方法返回的字节数组中有效数据长度。通常它与整个字节数组长度不等。18.9.2数据报服务器和客户下面的例子实现了一个非常简单的联网通信的客户和服务器。消息被写入服务器的窗口并通过网络写入客户端,在此它们被显示。//DemonstrateDatagrams.importjava.net.*;classWriteServer{publicstaticintserverPort=666;publicstaticintclientPort=999;publicstaticintbuffer_size=1024;publicstaticDatagramSocketds;publicstaticbytebuffer[]=newbyte[buffer_size];publicstaticvoidTheServer()throwsException{intpos=0;while(true){intc=System.in.read();switch(c){
50----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方case-1:System.out.println("ServerQuits.");return;case'\r':break;case'
51':ds.send(newDatagramPacket(buffer,pos,InetAddress.getLocalHost(),clientPort));pos=0;break;default:buffer[pos++]=(byte)c;}}}publicstaticvoidTheClient()throwsException{while(true){DatagramPacketp=newDatagramPacket(buffer,buffer.length);ds.receive(p);System.out.println(newString(p.getData(),0,p.getLength()));}}publicstaticvoidmain(Stringargs[])throwsException{if(args.length==1){ds=newDatagramSocket(serverPort);TheServer();}else{ds=newDatagramSocket(clientPort);TheClient();}}}该程序被DatagramSocket构造函数限制在本地机的两个端口间运行。试着运行该程序,在一个窗口中键入javaWriteServer这是在客户端的。然后运行javaWriteServer1这是在服务器端的。在服务器窗口中打印的任何东西在接受回车之后将被送到客户窗口。注意:该例题需要你的计算机与Internet相连。
52----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方18.10网络价值给你5个类InetAddress,Socket,ServerSocket,DatagramSocket和DatagramPacket,你可以编写现有的任何Internet协议。它们同样为Internet连接提供功能强大的低级控制。Java的网络包也完美地反映了Internet的状态。