|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
在ruby里才是一切皆对象。当然我不并不是很了解ruby,但是ruby确实是将语法简化得很好。web|web服务|web服务器基于Java的Web服务器事情道理1
一个Web服务器也被称为HTTP服务器,它经由过程HTTP协定与客户端通讯。这个客户端一般指的是Web扫瞄器。一个基于Java的Web服务器用到二个主要的类,java.net.Socket与java.net.ServerSocket,并经由过程HTTP动静通讯。因而,本文从会商HTTP与这二个类入手下手,然后我将注释一个与本文相干的复杂的Web使用。
TheHypertextTransferProtocol(HTTP)
HTTP是一种让Web服务器与扫瞄器(客户端)经由过程Internet发送与吸收数据的协定。它是一个哀求、呼应协定--客户端收回一个哀求,服务器呼应这个哀求。HTTP使用牢靠的TCP毗连,一般用的TCP80端口。它的第一个版本是HTTP/0.9,然后被HTTP/1.0代替。以后的版本是HTTP/1.1,由RFC2616(.pdf)界说。
本节次要对应HTTP1.1,充足使你充实了解由Web服务器程序收回的动静。假如你对加倍具体的常识有乐趣,能够参考RFC2616。
在HTTP中,客户端老是经由过程创建一个毗连与发送一个HTTP哀求来倡议一个事件。服务器不克不及自动往与客户端接洽,也不克不及给客户端收回一个回叫毗连。客户端与服务器端都能够提早中止一个毗连。比方,当用一个扫瞄器下载一个文件时,你能够经由过程点击“中断”键来中止文件的下载,封闭与服务器的HTTP毗连。
HTTP哀求
一个HTTP哀求包括三个部分:
Method-URI-Protocol/Version办法-地点-版本
Requestheader哀求头
Entitybody哀求实体
上面是一个HTTP哀求实例:
POST/servlet/default.jspHTTP/1.1
Accept:text/plain;text/html
Accept-Language:en-gb
Connection:Keep-Alive
Host:localhost
Referer:http://localhost/ch8/SendDetails.htm
User-Agent:Mozilla/4.0(compatible;MSIE4.01;Windows98)
Content-Length:33
Content-Type:application/x-www-form-urlencoded
Accept-Encoding:gzip,deflate
LastName=Franks&FirstName=Michael
TheMethod-URI-Protocol/Version在这个哀求的第一行:
POST/servlet/default.jspHTTP/1.1
个中POST是哀求的范例。每一个客户端HTTP哀求能够是HTTP标准中指定的很多哀求范例中的一种。HTTP1.1撑持七品种型的哀求,它们是GET,POST,HEAD,OPTIONS,PUT,DELETE,TRACE。个中GET与POST是Internet使用中常常用到的二种哀求范例。
URI完全地指定了Internet资本。一个URI一般被剖析为绝对服务器的根目次。如许,它应当老是以一个/前缀入手下手。一个URL实践上是URI的一品种型。
Version指的是该HTTP哀求所用到的HTTP协定版本。
哀求头包括了客户端情况与哀求实体的一些有效的信息。比方它包括扫瞄器设定的言语、实体的长度等等。每条哀求头用回车换行符(CRLF)分隔。
一个十分主要的空行分隔了哀求头与实体,它标记实在体内容的入手下手。一些Internet开辟书本以为这个CRLF空行是HTTP哀求的第四个部分。
在下面的HTTP哀求中,实体只是复杂以下的一行:
LastName=Franks&FirstName=Michael
在一个典范的HTTP哀求中,哀求实体内容会长很多。
HTTP呼应
与哀求类似,HTTP呼应也由三部分构成:
Protocol-Statuscode-Description协定形态形貌代码
Responseheaders呼应头
Entitybody呼应实体
以下是一个HTTP呼应的实例:
HTTP/1.1200OK
Server:Microsoft-IIS/4.0
Date:Mon,3Jan199813:13:33GMT
Content-Type:text/html
Last-Modified:Mon,11Jan199813:23:42GMT
Content-Length:112
<html>
<head>
<title>HTTPResponseExample</title></head><body>
WelcometoBrainySoftware
</body>
</html>
呼应头的第一行相似哀求头的第一行,告知你所用的协定是HTTP1.1,哀求乐成(200=success),和没有任何成绩。
呼应头相似哀求头也包括了一些有效的信息。呼应的实体呼应自己的HTML内容。头与实体之间由回车换行的空行(CRLF)分隔。
Socket类
一个socket是一个收集毗连的端点,它使得一个使用能够从收集读与写。在分歧电脑上的二个使用软件可以经由过程收发字撙节而相互通讯。要发一个信息到另外一个使用程序,你必要晓得它的IP地点,和它的socket端标语。在Java中,一个socket用java.net.Socket来完成。
要创立一个socket,你能够用Socket类中几个构建办法中的一个。个中一个承受主机名与端标语作为参数:
newSocket("yahoo.com",80);
一旦你乐成地创立了一个Socket类的实例,你就能够用它往发送与吸收字撙节了。要发送字撙节,你必要呼唤Socket类的getOutputStream办法来失掉一个java.io.OutputSteam对象。要发送文本到远程的程序,你一般必要从前往的OutputStream创立一个java.io.PrintWriter对象。要从毗连的另外一端吸收字撙节,你必要呼唤Socket类的getInputStream办法,它前往一个java.io.InputStream对象。
以下代码创立一个能够与当地HTTP服务器通讯的socket(127.0.0.1暗示一个当地的主机),发送一个HTTP哀求,并吸收从服务器的呼应。它还创立一个StringBuffer对象来承受呼应,并打印到把持台。
Socketsocket=newSocket("127.0.0.1","8080");
OutputStreamos=socket.getOutputStream();
booleanautoflush=true;
PrintWriterout=newPrintWriter(socket.getOutputStream(),
autoflush);
BufferedReaderin=newBufferedReader(
newInputStreamReader(socket.getInputStream()));
//sendanHTTPrequesttothewebserver
out.println("GET/index.jspHTTP/1.1");
out.println("Host:localhost:8080");
out.println("Connection:Close");
out.println();
//readtheresponse
booleanloop=true;
StringBuffersb=newStringBuffer(8096);
while(loop){
if(in.ready()){
inti=0;
while(i!=-1){
i=in.read();
sb.append((char)i);
}
loop=false;
}
Thread.currentThread().sleep(50);
}
//displaytheresponsetotheoutconsole
System.out.println(sb.toString());
socket.close();
注重要从web服务器失掉准确的呼应,你必需要发送用HTTP协定编译了的HTTP哀求。假如你看了下面的HTTP部分,你应当可以了解下面代码中的HTTP哀求。
编者注:这篇文章节选自budi本人出书的书<Tomcat内情>。你能够在他的网站失掉更多的相干材料。
基于Java的Web服务器事情道理2
fajaven译发文工夫:2003.09.1217:00:38
ServerSocket类
Socket类形貌的是“客户端”socket,当你必要创立与远程服务程序毗连时必要用到它。假如你想完成一个服务程序,如HTTP服务器大概FTP服务器,则必要别的分歧的办法。这是由于你的服务器必需随时服务,它不晓得甚么时分会有一个客户端程序必要毗连它。
由于这个目标,你必要用到java.net.ServerSocket这个类,它是服务器端socket的一个完成。服务器端socket守候来自客户真个毗连哀求。一旦它收到一个毗连哀求,它创立一个socket实例来与客户端举行通讯。
要创立服务器端socket,必要用到ServerSocket类供应的四个构建办法中的一个。你必要指定服务器端socket侦听的IP地点与端标语。对照典范地,这个IP地点能够是127.0.0.1,意义是该服务器端socket侦听的是当地呆板。服务器端socket侦听的IP地点指的是绑定地点。服务器端socket另外一个主要的属性是行列长度,即它回绝哀求前所承受的最年夜哀求列队长度。
ServerSocket类的构建办法之一以下:
publicServerSocket(intport,intbackLog,InetAddressbindingAddress);
关于这个构建办法,绑定地点必需是java.net.InetAddress类的实例。创立一个InetAddress类的对象的复杂办法是呼唤其静态办法getByName,传送一个包括主机名的字符串。
InetAddress.getByName("127.0.0.1");
以下行的代码创立了一个服务器端socket,它侦听当地呆板的8080端口,限定行列长度为1。
newServerSocket(8080,1,InetAddress.getByName("127.0.0.1"));
一旦有了一个ServerSocket实例,就能够经由过程呼唤其accept办法来让它守候出去的链接哀求。这个办法只要当吸收到哀求时才前往,它前往的是Socket类的实例。这个Socket对象就能够用来从客户端使用程序发送与吸收字撙节,正如上节听说的那样。实践上,accept办法是本文例子顶用到的独一办法。
使用实例
我们的web服务器程序是ex01.pyrmont包的一部分,它包括三个类:HttpServer;Request;Response。
全部程序的出口(静态main办法)是HttpServer类。它创立一个HttpServer的实例,并呼唤其await办法。正如名字表达的,await在一个特定的端口守候HTTP哀求,处置它们,并前往呼应给客户端。它坚持守候形态,直到收到中断命令。(用办法名await取代wait,是由于System中有一个主要的与线程相干的办法)
这个程序只从一个特定的目次发送静态资本,如HTML与图象文件。它只撑持没有文件头(如日期与cookie)的情形。如今我们将在以下的几节中看一下这三个类。
HttpServer类
HttpServer完成了一个web服务器,它能够供应(serve)特定目次及其子目次下的静态资本。这个特定的目次由publicstaticfinalWEB_ROOT指定。
WEB_ROOT初始化以下:
publicstaticfinalStringWEB_ROOT=
System.getProperty("user.dir")+File.separator+"webroot";
代码列表中包括了一具叫做webroot的目次,内里有一些静态的资本,你能够用来测试本使用。你也能够看到一个servlet,在我的下一篇文章将会被用到:“Servlets容器是如何事情的”。
为了哀求一个静态的资本,在扫瞄器的地点栏输出如是地点:http://machinename:port/staticResources
假如你从分歧的呆板上发送哀求到运转本使用的呆板,则machinename是运转使用呆板的呆板名或IP地点,port是8080,staticResources是被哀求的文件称号,它必需包括在WEB_ROOT目次内。
比方,假如你用统一台电脑来测试这个使用,你想要HttpServer发送index.html这个文件,用以下的地点:http://localhost:8080/index.html
要中断服务,只必要从扫瞄器发送一个中断(shutdown)命令,即在扫瞄器的地点栏输出host:port字段后,加上事后界说好的字符串。在我们的HttpServer类中,中断命令被界说为SHUTDOWN,一个staticfinal变量。
privatestaticfinalStringSHUTDOWN_COMMAND="/SHUTDOWN";
因而,要中断服务,你能够如许:http://localhost:8080/SHUTDOWN
如今,让我们看一以下表1.1中给出的await办法。代码列表前面将对这段代码做一些注释。
Listing1.1.TheHttpServerclassawaitmethod
publicvoidawait(){
ServerSocketserverSocket=null;
intport=8080;
try{
serverSocket=newServerSocket(port,1,
InetAddress.getByName("127.0.0.1"));
}
catch(IOExceptione){
e.printStackTrace();
System.exit(1);
}
//Loopwaitingforarequest
while(!shutdown){
Socketsocket=null;
InputStreaminput=null;
OutputStreamoutput=null;
try{
socket=serverSocket.accept();
input=socket.getInputStream();
output=socket.getOutputStream();
//createRequestobjectandparse
Requestrequest=newRequest(input);
request.parse();
//createResponseobject
Responseresponse=newResponse(output);
response.setRequest(request);
response.sendStaticResource();
//Closethesocket
socket.close();
//checkifthepreviousURIisashutdowncommand
shutdown=request.getUri().equals(SHUTDOWN_COMMAND);
}
catch(Exceptione){
e.printStackTrace();
continue;
}
}
}
await办法以创立一个ServerSocket实例入手下手,然落后进一个while的轮回。
serverSocket=newServerSocket(
port,1,InetAddress.getByName("127.0.0.1"));
...
//Loopwaitingforarequest
while(!shutdown){
...
}
在while轮回中的代码,运转到ServerSocket的accept办法即中断。这个办法只要在8080端口吸收到HTTP哀求才前往:
socket=serverSocket.accept();
收到哀求后,await办法从accept办法前往的Socket实例中比及java.io.InputStream与java.io.OutputStream:
input=socket.getInputStream();
output=socket.getOutputStream();
然后await办法创立一个Request对象,呼唤它的parse办法来剖析这个原始的HTTP哀求:
//createRequestobjectandparse
Requestrequest=newRequest(input);
request.parse();
下一步,await办法创立一个Response对象并把Request对象设置给它,呼唤它的sendStaticResource办法:
//createResponseobject
Responseresponse=newResponse(output);
response.setRequest(request);
response.sendStaticResource();
最初,await办法封闭Socket,呼唤Request的getUri办法来反省HTTP哀求的地点是不是是一个中断命令。假如是,则shutdown变量被设置为true,程序加入while轮回:
//Closethesocket
socket.close();
//checkifthepreviousURIisashutdowncommand
shutdown=request.getUri().equals(SHUTDOWN_COMMAND);
基于Java的Web服务器事情道理3
fajaven发文工夫:2003.09.1217:11:54
Request类
Request类对应HTTP哀求。创立这个类的实例,并传给它从Socket取得的InputStream对象,从而捕捉与客户真个通讯。呼唤InputStream对象的read办法中的一个就能够失掉HTTP哀求的原始数据。
Request类有二个public办法parse与getUri。parse办法剖析HTTP哀求的原始数据。它做的事变未几--独一它使之无效的信息是HTTP哀求的URI,这个经由过程呼唤公有办法parseUri来取得。parseUri办法把URI作为一个变量。挪用getUri办法能够失掉HTTP哀求的URI。
要分明parse与parseUri的事情道理,你必要晓得HTTP哀求的布局,由RFC2616界说。
一个HTTP哀求包含三个部分:Requestline;Headers;Messagebody。
如今,我们只必要存眷HTTP哀求的第一部分--哀求行。哀求行以办法暗号入手下手,接着是哀求的URI与协定版本,以回车换行符停止。哀求行的元素之间以空格分隔。比方,一个用GET办法的index.html文件的哀求行以下:
GET/index.htmlHTTP/1.1
parse办法从socket的InputStream传送给Request对象中读取字撙节,把这个字节数组存在缓冲里。然后,它把buffer字节数组里的字节放进叫做request的StringBuffer对象中,再把StringBuffer交换成String传送给parseUri办法。
parse办法的代码如列表1.2
Listing1.2.TheRequestclassparsemethod
publicvoidparse(){
//Readasetofcharactersfromthesocket
StringBufferrequest=newStringBuffer(2048);
inti;
byte[]buffer=newbyte[2048];
try{
i=input.read(buffer);
}
catch(IOExceptione){
e.printStackTrace();
i=-1;
}
for(intj=0;j<i;j++){
request.append((char)buffer[j]);
}
System.out.print(request.toString());
uri=parseUri(request.toString());
}
parseUri办法查找哀求行的第一个与第二个空格,从而从哀求行取得了URI。列表1.3展现了parseUri办法的代码。
Listing1.3.TheRequestclassparseUrimethod
privateStringparseUri(StringrequestString){
intindex1,index2;
index1=requestString.indexOf();
if(index1!=-1){
index2=requestString.indexOf(,index1+1);
if(index2>index1)
returnrequestString.substring(index1+1,index2);
}
returnnull;
}
Response类
Response类形貌HTTP呼应。它的构建办法承受OutputStream对象,以下:
publicResponse(OutputStreamoutput){
this.output=output;
}
Response对象经由过程传送从socket取得的OutputStream对象到HttpServer类的await办法而创立。
Response类有二个大众办法setRequest与setStaticResource。setRequest用来传送Request对象到Response对象。它对照复杂,代码如列表1.4所示:
Listing1.4.TheResponseclasssetRequestmethod
publicvoidsetRequest(Requestrequest){
this.request=request;
}
sendStaticResource办法用来发送静态的资本,比方HTML文件。它的完成如列表1.5所示:
Listing1.5.TheResponseclasssendStaticResourcemethod
publicvoidsendStaticResource()throwsIOException{
byte[]bytes=newbyte[BUFFER_SIZE];
FileInputStreamfis=null;
try{
Filefile=newFile(HttpServer.WEB_ROOT,request.getUri());
if(file.exists()){
fis=newFileInputStream(file);
intch=fis.read(bytes,0,BUFFER_SIZE);
while(ch!=-1){
output.write(bytes,0,ch);
ch=fis.read(bytes,0,BUFFER_SIZE);
}
}
else{
//filenotfound
StringerrorMessage="HTTP/1.1404FileNotFound
"+
"Content-Type:text/html
"+
"Content-Length:23
"+
"
"+
"<h1>FileNotFound</h1>";
output.write(errorMessage.getBytes());
}
}
catch(Exceptione){
//thrownifcannotinstantiateaFileobject
System.out.println(e.toString());
}
finally{
if(fis!=null)
fis.close();
}
}
SendStaticResource办法十分复杂。它起首经由过程传送父与子目次到File类的构建办法从而实例化java.io.File类。
FilefilenewFile(HttpServer.WEB_ROOT,request.getUri());
然后反省这个文件是不是存在。假如存在,则sendStaticResource办法传送File对象创立java.io.FileInputStream对象。然后挪用FileInputStream的read办法,并把字节数组写到OutputStream对象output。就如许,静态资本的内容作为原始数据被发送到扫瞄器。
if(file.exists()){
fis=newFileInputStream(file);
intch=fis.read(bytes,0,BUFFER_SIZE);
while(ch!=-1){
output.write(bytes,0,ch);
ch=fis.read(bytes,0,BUFFER_SIZE);
}
}
假如文件不存在,sendStaticResource发送一个毛病信息到扫瞄器。
StringerrorMessage="HTTP/1.1404FileNotFound
"+
"Content-Type:text/html
"+
"Content-Length:23
"+
"
"+
"<h1>FileNotFound</h1>";
output.write(errorMessage.getBytes());
编译与运转使用程序
要编纂与运转本文的使用,起首你必要解压源码zip文件。间接解压出来的目次被称为事情目次,它有三个子目次:src/,classes/,lib/。要编译使用,从事情目次输出以下命令:
javac-d.src/ex01/pyrmont/*.java
-d选项把了局写到以后目次,而不是src/目次。
要运转使用,在以后事情目次输出以下命令:
javaex01.pyrmont.HttpServer
测试这个使用,翻开你的扫瞄器,在地点栏输出以下地点:http://localhost:8080/index.html
你将在你的扫瞄器看到index.html显现出来,如所示。
:web服务器的输入显现
在把持台,你看到以下的内容:
GET/index.htmlHTTP/1.1
Accept:*/*
Accept-Language:en-us
Accept-Encoding:gzip,deflate
User-Agent:Mozilla/4.0(compatible;MSIE4.01;Windows98)
Host:localhost:8080
Connection:Keep-Alive
GET/images/logo.gifHTTP/1.1
Accept:*/*
Referer:http://localhost:8080/index.html
Accept-Language:en-us
Accept-Encoding:gzip,deflate
User-Agent:Mozilla/4.0(compatible;MSIE4.01;Windows98)
Host:localhost:8080
Connection:Keep-Alive
总结
在这篇文章中(分为三个部分),你看到了一个复杂的web服务器的事情道理。本文相干的使用只包含了三个类,功效是不周全的。但是,它仍不掉为一个好的进修工具。
windows系统样,他们做了什么事或者留了一些后门程序,谁都不知道,二,java开发是跨平台,任何系统上都可以运行,对于保密型系统和大型系统开发这是必要的 |
|