JavaWeb工作原理
[JavaWeb工作原理][第一章]一什么是JavaWeb?
JavaWeb是用Java技术来解决相关web互联网领域的技术总和。web包括:web服务器和web客户端两部分,在第一个项目(贷款计息查询服务器)的时候已经知道在Web服务器的作用是接受客户端请求,然后向客户端返回一些结果.浏览器的作用是允许用户请求服务器上的某个资源,并且向用户显示请求的结果,HTML用于告诉浏览器怎样向用户显示内容,HTTP是WEB上客户端和服务器之间通信所用的协议
二HTTP协议
Http是一种超文本传输协议(HyperTextTransferProtocol),他是一套计算机在网中通信的一种规则,在TCP/IP体系结构中,HTTP属于应用层协议,位于TCP/IP协议的顶层.HTTP是一种无状态的协议,意思是指在WEB浏览器和WEB服务器之间不需要建立持久的连接,HTTP定义的事物处理由以下四步组成:
1.客户端和WEB服务器建立连接
a)客户端和服务器的连接就是与客户端与服务器的一个TCPSocket套接字连接2.客户端发送HTTP请求
a)请求包含:请求行--请求行是一个ACCII文本行,由请求的HTTP方法,请求的
URL,HTTP版本组成,中间用空格分开,
b)请求头---HTTP协议使用HTTP头来传递请求的元信息,
c)空行---发送回车符和退行,通知服务器以下不再有请求头
d)消息体--HTTP请求中带有查询字符串时,如果是GET方法,查询字符串或表单数据附加在请求行中,那么消息体就没有内容,如果是POST方法,查询字符串或表单数据就添加在消息体重
3.服务器端接收客户端的HTTP请求,生成HTTP相应回发
a)响应包含:状态行---每个HTTP响应以一个状态行开头,它由HTTP协议版本,
响应状态码,响应描述组成,中间用空格分开b)响应头---响应头与请求头一样,也是一个用冒号分隔符的名称/值对,冒号前面
是HTTP头得名称,后面是HTTP头得值c)空行---发送回车符和退行,通知服务器以下不再有响应头
d)消息体---要发送回客户端的HTML文档或其他要显示的内容等,WEB服务器
把要发送给客户端的文档信息放在消息体中
4.服务器端关闭连接,客户端解析并回发响应,恢复页面
a)HTTP响应到达客户端后,浏览器先解析HTTP响应中的状态行,查看请求是否
成功的状态代码,然后开始一步步解析响应
三WEB服务器缺陷与CGI
WEB服务是被设计用来向客户端提供HTTP服务的,它只是能向客户端提供静态网页内容.我们知道,静态网页只是原封不动的待在WEB服务器目录中,服务器知道静态页面,并把它原样传回到客户端,每个客户端看到的页面都是一样的,所以WEB服务器它本身并不具备动态页面,所以在最早有了解决办法CGI,
CGI即通用网关接口(CommonGateWayInterface),是最早用于创建动态服务器端内容的一种技术,使用CGI,WEB服务器可以将客户端的请求传递给一个外部程序,这个外部程序可以执行,创建内容,并且将响应传递给客户端,
但是他在处理一个请求的时候还行,但是在处理对个请求的时候是没有一个用户请求就新开一个进程,我们都知道进程是有独立的内存空间的,如果请求用户多的时候那么就会导致服务器的崩溃,
四Java的解决方案
在java里,Servlet以及web容器,被设计用来解决CGI的问题,为WEB开发者创建一个健壮的服务器环境,
一、Servlet
a)Servlet是J2EE规范,
b)它是一个普通的JAVA类,集成于HttpServlet,用于处理动态页面的响应
c)它是与平台无关的JAVA类,能够编译成平台中立的字节码,从而被基于JAVA技术的WEB服务器动态装载和运行
d)Servlet在服务器端得工作主要是执行如下任务
i.读取客户端发送的显示和隐式数据
ii.生成结果
iii.向客户端发送显示数据(文档)和隐式数据(HTTP响应数据)
二、WEB容器
a)WEB容器主要是如Tomcat,Jboss,WebLogic,WebSphere,Oracle9iAS等,其中Tomcat是一种用的很广泛的Web容器,它是一个开放源代码的免费的中间件产品b)WEB容器必须对Servlet支持以下几点
i.通信支持
ii.生命周期管理
iii.多线程支持iv.JSP支持v.处理安全性
三、Servlet与WEB容器配合处理请求和响应
a)与GUI类似,Servlet允许一个请求被一个程序处理.并且使用同样的程序产生动态的
响应,此外,Servlet特别定义了一个有效的生命周期,使得用单个进程管理所有请求成为可能,它消除了CGI的多进程缺陷,允许主进程在多个Servlet和多个请求之间共享内存资源.b)Servlet运行在一个主进程或者一个父进程中,每个用户发送请求信息到服务器,就会在Servlet进程里创建一个线程,它们共享一个资源c)最后,WEB容器和Servlet对请求和响应的处理如下
i.客户端向WEB服务器发起一个HTTP请求
ii.HTTP请求被WEB服务器几首,如果请求的是静态页面,则由WEB服务器负责
处理,如果请求的是JAVAWEB组件(Servlet或者JSP),则移交给WEB容器,iii.WEB容器根据Servlet的配置文件(web.xml),确定调用的具体Servlet类,并把request对象,response对象传给它
iv.Servlet通过request对象知道客户端的使用者是谁,客户的请求信息是什么和其
他的一些信息
v.一旦Servlet完成了请求的处理,WEB容器就会刷新response,把控制权返回给
WEB服务器
五JavaWeb应用程序的组成
1.配置文件---每个WEB应用程序包括一个配置文件,WEB.XML2.静态文件和JSP
3.类文件和包---WEB应用程序装载和管理自定义的JAVA代码
4.网页可以放在WEB应用程序的根目录下,根据动态网页或者静态网页放在不同的目
录里
5.图像一般会放在images子目录中,不过这是习惯,不是必须的
6.Servlet类,JavaBean类---编译为Class文件后是防在WEB-INF/classes目录的7.Lib目录用来包含应用程序任何所需要的jar文件8.标记描述其放在WEB-INF目录下
9.Applet程序放在应用的目录下
10.WEB-INF目录下存放web.xml部署描述文件器
剩下的WEB容器Tomcat主要是在实践中应用,在这里不做总结
扩展阅读:JavaWeb工作原理
浅析基于Java的Web服务器工作原理
一个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/htmlAccept-Language:en-gb
Connection:Keep-Alive
Host:localhost
Referer:
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:1
WelcometoBrainySoftware
响应头的第一行类似请求头的第一行,告诉你所用的协议是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译发文时间:201*.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容器是怎样工作的”。
为了请求一个静态的资源,在浏览器的地址栏输入如是地址::port/staticResources
如果你从不同的机器上发送请求到运行本应用的机器,则machinename是运行应用机器的机器名或IP地址,port是8080,staticResources是被请求的文件名称,它必须包含在WEB_ROOT目录内。
例如,如果你用同一台电脑来测试这个应用,你想要HttpServer发送index.html这个文件,用以下的地址::8080/index.html
要停止服务,只需要从浏览器发送一个停止(shutdown)命令,即在浏览器的地址栏输入host:port字段后,加上预先定义好的字符串。在我们的HttpServer类中,停止命令被定义为SHUTDOWN,一个staticfinal变量。
privatestaticfinalStringSHUTDOWN_COMMAND="/SHUTDOWN";
因此,要停止服务,你可以这样::8080/SHUTDOWN现在,让我们看一下列表1.1中给出的await方法。代码列表后面将对这段代码做一些解释。
Listing1.1.TheHttpServerclass"awaitmethod
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发文时间:201*.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.TheRequestclass"parsemethod
publicvoidparse(){
//ReadasetofcharactersfromthesocketStringBufferrequest=newStringBuffer(2048);inti;
byte[]buffer=newbyte[2048];try{
i=input.read(buffer);}
catch(IOExceptione){
e.printStackTrace();i=-1;}
for(intj=0;jrequest.append((char)buffer[j]);}
System.out.print(request.toString());
uri=parseUri(request.toString());}
parseUri方法查找请求行的第一个与第二个空格,从而从请求行获得了URI。列表1.3展示了parseUri方法的代码。
Listing1.3.TheRequestclass"parseUrimethod
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.TheResponseclass"setRequestmethod
publicvoidsetRequest(Requestrequest){
this.request=request;}
sendStaticResource方法用来发送静态的资源,例如HTML文件。它的实现如列表1.5所示:
Listing1.5.TheResponseclass"sendStaticResourcemethod
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\\r\\n"+
"Content-Type:text/html\\r\\n"+
"Content-Length:23\\r\\n"+"\\r\\n"+"
FileNotFound";
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\\r\\n"+
"Content-Type:text/html\\r\\n"+
"Content-Length:23\\r\\n"+"\\r\\n"+"
FileNotFound";
output.write(errorMessage.getBytes());
编译与运行应用程序
要编辑与运行本文的应用,首先你需要解压源码zip文件。直接解压出来的目录被称为工作目录,它有三个子目录:src/,classes/,lib/。要编译应用,从工作目录输入如下命令:
javac-d.src/ex01/pyrmont/*.java
-d选项把结果写到当前目录,而不是src/目录。
要运行应用,在当前工作目录输入如下命令:
javaex01.pyrmont.HttpServer
测试这个应用,打开你的浏览器,在地址栏输入如下地址::8080/index.html
你将在你的浏览器看到index.html显示出来,如图1所示。
图1: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::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服务器的工作原理。本文相关的应用只包括了三个类,功能是不全面的。然而,它仍不失为一个好的学习工具。
(责任编辑:张明燕)
Java的网络编程:用Java实现Web服务器
作者:谷和启发文时间:201*.12.2615:35:57
HTTP协议
超文本传输协议(HTTP)是位于TCP/IP协议的应用层,是最广为人知的协议,也是互连网中最核心的协议之一,同样,HTTP也是基于C/S或B/S模型实现的。事实上,我们使用的浏览器如Netscape或IE是实现HTTP协议中的客户端,而一些常用的Web服务器软件如Apache、IIS和iPlanetWebServer等是实现HTTP协议中的服务器端。Web页由服务端资源定位,传输到浏览器,经过浏览器的解释后,被客户所看到。
Web的工作基于客户机/服务器计算模型,由Web浏览器(客户机)和Web服务器(服务器)构成,两者之间采用超文本传送协议(HTTP)进行通信。HTTP协议是Web浏览器和Web服务器之间的应用层协议,是通用的、无状态的、面向对象的协议。
一个完整的HTTP协议会话过程包括四个步骤:
◆连接,Web浏览器与Web服务器建立连接,打开一个称为Socket(套接字)的虚拟文件,此文件的建立标志着连接建立成功;
◆请求,Web浏览器通过Socket向Web服务器提交请求。HTTP的请求一般是GET或POST命令(POST用于FORM参数的传递);
◆应答,Web浏览器提交请求后,通过HTTP协议传送给Web服务器。Web服务器接到后,进行事务处理,处理结果又通过HTTP传回给Web浏览器,从而在Web浏览器上显示出所请求的页面;
◆关闭连接,应答结束后Web浏览器与Web服务器必须断开,以保证其它Web浏览器能够与Web服务器建立连接。
Java实现Web服务器功能的程序设计
编程思路
根据上述HTTP协议的会话过程,本实例中实现了GET请求的Web服务器程序的方法,方法如下:
通过创建ServerSocket类对象,侦听用户指定的端口(为8080),等待并接受客户机请求到端口。创建与Socket相关联的输入流和输出流,然后读取客户机的请求信息。若请求类型是GET,则从请求信息中获取所访问的HTML文件名;如果HTML文件存在,则打开HTML文件,把HTTP头信息和HTML文件内容通过Socket传回给Web浏览器,然后关闭文件,否则发送错误信息给Web浏览器。最后关闭与相应Web浏览器连接的Socket。
用Java编写Web服务器httpServer.java文件的源代码如下:
//httpServer.java
importjava.net.*;
importjava.io.*;
importjava.util.*;
importjava.lang.*;
publicclasshttpServer{
publicstaticvoidmain(Stringargs[]){intport;
ServerSocketserver_socket;
//读取服务器端口号try{
port=Integer.parseInt(args[0]);}
catch(Exceptione){
port=8080;}try{
//监听服务器端口,等待连接请求
server_socket=newServerSocket(port);
System.out.println("httpServerrunningonport"+
server_socket.getLocalPort());
//显示启动信息
while(true){
Socketsocket=server_socket.accept();
System.out.println("Newconnectionaccepted"+
socket.getInetAddress()+
":"+socket.getPort());
//创建分线程try{
httpRequestHandlerrequest=
newhttpRequestHandler(socket);
Threadthread=newThread(request);
//启动线程
thread.start();}
catch(Exceptione){
System.out.println;}}}
catch(IOExceptione){
System.out.println;}}}
classhttpRequestHandlerimplementsRunnable{
finalstaticStringCRLF="\\r\\n";
Socketsocket;
InputStreaminput;
OutputStreamoutput;
BufferedReaderbr;
//构造方法
publichttpRequestHandler(Socketsocket)throwsException{
this.socket=socket;
this.input=socket.getInputStream();
this.output=socket.getOutputStream();
this.br=
newBufferedReader(newInputStreamReader(socket.getInputStream()));}
//实现Runnable接口的run()方法
publicvoidrun(){try{
processRequest();}
catch(Exceptione){
System.out.println;}}
privatevoidprocessRequest()throwsException{
while(true){
//读取并显示Web浏览器提交的请求信息
StringheaderLine=br.readLine();
System.out.println("Theclientrequestis"+headerLine);
if(headerLine.equals(CRLF)||headerLine.equals(""))break;
StringTokenizers=newStringTokenizer(headerLine);
Stringtemp=s.nextToken();
if(temp.equals("GET")){
StringfileName=s.nextToken();
fileName="."+fileName;
//打开所请求的文件
FileInputStreamfis=null;
booleanfileExists=true;try{
fis=newFileInputStream(fileName);}
catch(FileNotFoundExceptione){
fileExists=false;}
//完成回应消息
StringserverLine="Server:asimplejavahttpServer";
StringstatusLine=null;
StringcontentTypeLine=null;
StringentityBody=null;
StringcontentLengthLine="error";
if(fileExists){
statusLine="HTTP/1.0200OK"+CRLF;
contentTypeLine="Content-type:"+
contentType(fileName)+CRLF;
contentLengthLine="Content-Length:"
+(newInteger(fis.available())).toString()
+CRLF;}else{
statusLine="HTTP/1.0404NotFound"+CRLF;
contentTypeLine="text/html";
entityBody=""+""+
"404NotFound"+"
usage::port/"
+"fileName.html";}
//发送到服务器信息
output.write(statusLine.getBytes());
output.write(serverLine.getBytes());
output.write(contentTypeLine.getBytes());
output.write(contentLengthLine.getBytes());
output.write(CRLF.getBytes());//发送信息内容
if(fileExists){
sendBytes(fis,output);
fis.close();}else{
output.write(entityBody.getBytes());}}}
//关闭套接字和流try{
output.close();
br.close();
socket.close();}
catch(Exceptione){}}
privatestaticvoidsendBytes(FileInputStreamfis,OutputStreamos)
throwsException{
//创建一个1Kbuffer
byte[]buffer=newbyte[1024];
intbytes=0;
//将文件输出到套接字输出流中
while((bytes=fis.read(buffer))!=-1){
os.write(buffer,0,bytes);}}
privatestaticStringcontentType(StringfileName){
if(fileName.endsWith(".htm")||fileName.endsWith(".html")){
return"text/html";}
return"fileName";}}
编程技巧说明◆主线程设计
主线程的设计就是在主线程httpServer类中实现了服务器端口的侦听,服务器接受一个客户端请求之后创建一个线程实例处理请求,代码如下:
importjava.net.*;
importjava.io.*;
importjava.util.*;
importjava.lang.*;
publicclasshttpServer{
publicstaticvoidmain(Stringargs[]){port;
ServerSocketserver_socket;
//读取服务器端口号try{
port=Integer.parseInt(args[0]);}
catch(Exceptione){
port=8080;}try{
//监听服务器端口,等待连接请求
server_socket=newServerSocket(port);
System.out.println("httpServerrunningonport"
+server_socket.getLocalPort());....................
◆连接处理分线程设计
在分线程httpRequestHandler类中实现了HTTP协议的处理,这个类实现了Runnable接口,代码如下:
classhttpRequestHandlerimplementsRunnable{
finalstaticStringCRLF="\\r\\n";
Socketsocket;
InputStreaminput;
OutputStreamoutput;
BufferedReaderbr;
//构造方法
publichttpRequestHandler(Socketsocket)throwsException{
this.socket=socket;
//得到输入输出流
this.input=socket.getInputStream();
this.output=socket.getOutputStream();
this.br=
newBufferedReader(newInputStreamReader(socket.getInputStream()));}
//实现Runnable接口的run()方法
publicvoidrun(){try{
processRequest();}
catch(Exceptione){
System.out.println;}}
◆构建processRequest()方法来处理信息的接收和发送
作为实现Runnable接口的主要内容,在run()方法中调用processRequest()方法来处理客户请求内容的接收和服务器返回信息的发送,代码如下:
privatevoidprocessRequest()throwsException{
while(true){
//读取并显示Web浏览器提交的请求信息
StringheaderLine=br.readLine();
System.out.println("Theclientrequestis"+headerLine);
if(headerLine.equals(CRLF)||headerLine.equals(""))break;
//根据请求字符串中的空格拆分客户请求
StringTokenizers=newStringTokenizer(headerLine);
Stringtemp=s.nextToken();
if(temp.equals("GET")){
StringfileName=s.nextToken();
fileName="."+fileName;
.............
.............
在processRequest()方法中得到客户端请求后,利用一个StringTokenizer类完成了字符串的拆分,这个类可以实现根据字符串中指定的分隔符(缺省为空格)将字符串拆分成为字串的功能。利用nextToken()方法依次得到这些字串;sendBytes()方法完成信息内容的发送,contentType()方法用于判断文件的类型。
显示Web页面
显示Web页面的index.html文件代码如下:
*********欢迎你的到来!*********
这是一个用Java语言实现的Web服务器
--------------------------------------------------------------------------------
运行实例
为了测试上述程序的正确性,将编译后的httpServer.class、httpRequestHandler.class和上面的index.html文件置于网络的某台主机的同一目录中。
首先运行服务器程序javahttpServer8080,服务器程序运行后显示端口信息“httpServerruningonport8080”,然后在浏览器的地址栏中输入:8080/index.html,就可以正确显示网页,同时在显示“httpServerruningonport8080”窗口中服务器会出现一些信息。
友情提示:本文中关于《JavaWeb工作原理》给出的范例仅供您参考拓展思维使用,JavaWeb工作原理:该篇文章建议您自主创作。
来源:网络整理 免责声明:本文仅限学习分享,如产生版权问题,请联系我们及时删除。
《JavaWeb工作原理》
由互联网用户整理提供,转载分享请保留原作者信息,谢谢!
http://m.bsmz.net/gongwen/585498.html
- 下一篇:JavaWeb工作流程