java实现web服务器.docx

上传人:b****5 文档编号:5046174 上传时间:2022-12-12 格式:DOCX 页数:19 大小:23.76KB
下载 相关 举报
java实现web服务器.docx_第1页
第1页 / 共19页
java实现web服务器.docx_第2页
第2页 / 共19页
java实现web服务器.docx_第3页
第3页 / 共19页
java实现web服务器.docx_第4页
第4页 / 共19页
java实现web服务器.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

java实现web服务器.docx

《java实现web服务器.docx》由会员分享,可在线阅读,更多相关《java实现web服务器.docx(19页珍藏版)》请在冰豆网上搜索。

java实现web服务器.docx

java实现web服务器

TheHypertextTransferProtocol(HTTP)

它是一个请求、响应协议--客户端发出一个请求,服务器响应这个请求。

HTTP运用可靠的TCP连接,通常用的TCP80端口。

它的第一个版本是HTTP/

0."9,然后被HTTP/

1."0取代。

当前的版本是HTTP/

1."1,由RFC2616(.pdf)定义。

本节主要对应HTTP

1."1,足够使你充分理解由Web服务器程序发出的消息。

如果你对更加详细的知识有兴趣,可以参考RFC

2616。

"

在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

Refer:

http:

//localhost/ch8/SendDetails.htm

User-Agent:

Mozilla/

4."01;Windows98)

Content-Length:

33

Content-Type:

Accept-Encoding:

gzip,deflate

LastName=Franks&FirstName=Michael

TheMethod-URI-Protocol/Version在这个请求的第一行:

POST/servlet/default.jspHTTP/

1."1

其中POST是请求的类型。

每个客户端HTTP请求可以是HTTP规范中指定的许多请求类型中的一种。

HTTP

Version指的是该HTTP请求所用到的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

响应头的第一行类似请求头的第一行,告诉你所用的协议是HTTP

1."1,请求成功(200=success),以及没有任何问题。

响应头类似请求头也包含了一些有用的信息。

响应的实体响应本身的HTML内容。

头与实体之间由回车换行的空行(CRLF)分开。

Socket类

要创建一个socket,你可以用Socket类中几个构建方法中的一个。

其中一个接受主机名与端口号作为参数:

一旦你成功地创建了一个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","80");

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:

80");

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请求。

编者注:

基于Java的Web服务器工作原理2

fajaven译发文时间:

2003."0

9."1217:

00:

38

ServerSocket类

Socket类描述的是“客户端”socket,当你需要创建与远程服务程序连接时需要用到它。

如果你想实现一个服务程序,如HTTP服务器或者FTP服务器,则需要另外不同的方法。

要创建服务器端socket,需要用到ServerSocket类提供的四个构建方法中的一个。

你需要指定服务器端socket侦听的IP地址与端口号。

比较典型地,这个IP地址可以是12

7."

0.

0."1,意思是该服务器端socket侦听的是本地机器。

服务器端socket侦听的IP地址指的是绑定地址。

服务器端socket另一个重要的属性是队列长度,即它拒绝请求前所接受的最大请求排队长度。

ServerSocket类的构建方法之一如下:

127."

0.

0."1");

以下行的代码创建了一个服务器端socket,它侦听本地机器的80端口,限制队列长度为

1。

"

127."

0.

0."1"));

一旦有了一个ServerSocket实例,就可以通过呼叫其accept方法来让它等待进来的链接请求。

这个方法只有当接收到请求时才返回,它返回的是Socket类的实例。

这个Socket对象就可以用来从客户端应用程序发送与接收字节流,正如上节据说的那样。

实际上,accept方法是本文例子中用到的唯一方法。

应用实例

我们的web服务器程序是ex

01."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是80,staticResources是被请求的文件名称,它必须包含在WEB_ROOT目录内。

例如,如果你用同一台电脑来测试这个应用,你想要HttpServer发送index.html这个文件,用以下的地址:

http:

//localhost:

80/index.html

要停止服务,只需要从浏览器发送一个停止(shutdown)命令,即在浏览器的地址栏输入host:

port字段后,加上预先定义好的字符串。

在我们的HttpServer类中,停止命令被定义为SHUTDOWN,一个staticfinal变量。

privatestaticfinalStringSHUTDOWN_COMMAND="/SHUTDOWN";

因此,要停止服务,你可以这样:

http:

//localhost:

80/SHUTDOWN

现在,让我们看一下列表

1."1中给出的await方法。

代码列表后面将对这段代码做一些解释。

Listing

1."

1.TheHttpServerclass'awaitmethod

publicvoidawait(){

ServerSocketserverSocket=null;

intport=80;

try{

serverSocket=newServerSocket(port,1,

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();

shutdown=request.getUri().equals(SHUTDOWN_COMMAND);}catch(Exceptione){

e.printStackTrace();

continue;}}}await方法以创建一个ServerSocket实例开始,然后进入一个while的循环。

serverSocket=newServerSocket(

127."

0.

0."1"));

...

//Loopwaitingforarequest

while(!

shutdown){

...}在while循环中的代码,运行到ServerSocket的accept方法即停止。

这个方法只有在80端口接收到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();

shutdown=request.getUri().equals(SHUTDOWN_COMMAND);

基于Java的Web服务器工作原理3

fajaven发文时间:

2003."0

9."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

Listing

1."

2.TheRequestclass'parsemethod



publicvoidparse(){

//Readasetofcharactersfromthesocket

StringBufferrequest=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方法的代码。

Listing

1."

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所示:

Listing

1."

4.TheResponseclass'setRequestmethod

publicvoidsetRequest(Requestrequest){

this.request=request;}sendStaticResource方法用来发送静态的资源,例如HTML文件。

它的实现如列表

1."5所示:

Listing

1."

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:

t

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育 > 少儿英语

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1