一、http协议的作用原理
www是以internet作为传输媒介的一个应用系统,www网上最基本的传输单位是web网页。www的工作基于客户机/服务器计算模型,由web 浏览器(客户机)和web服务器(服务器)构成,两者之间采用超文本传送协议(http)进行通信。http协议是基于tcp/ip协议之上的协议,是web浏览器和web服务器之间的应用层协议,是通用的、无状态的、面向对象的协议。http协议的作用原理包括四个步骤:
(1) 连接:web浏览器与web服务器建立连接,打开一个称为socket(套接字)的虚拟文件,此文件的建立标志着连接建立成功。
(2) 请求:web浏览器通过socket向web服务器提交请求。http的请求一般是get或post命令(post用于form参数的传递)。get命令的格式为:
get 路径/文件名 http/1.0
文件名指出所访问的文件,http/1.0指出web浏览器使用的http版本。
(3) 应答:web浏览器提交请求后,通过http协议传送给web服务器。web服务器接到后,进行事务处理,处理结果又通过http传回给web浏览器,从而在web浏览器上显示出所请求的页面。
例:假设客户机与www.mycompany.com:8080/mydir/index.html建立了连接,就会发送get命令:get /mydir/index.html http/1.0.主机名为www.mycompany.com的web服务器从它的文档空间中搜索子目录mydir的文件index.html.如果找到该文件,web服务器把该文件内容传送给相应的web浏览器。
为了告知 web浏览器传送内容的类型,web服务器首先传送一些http头信息,然后传送具体内容(即http体信息),http头信息和http体信息之间用一个空行分开。
常用的http头信息有:
① http 1.0 200 ok
这是web服务器应答的第一行,列出服务器正在运行的http版本号和应答代码。代码“200 ok”表示请求完成。
② mime_version:1.0
它指示mime类型的版本。
③ content_type:类型
这个头信息非常重要,它指示http体信息的mime类型。如:content_type:text/html指示传送的数据是html文档。
④ content_length:长度值
它指示http体信息的长度(字节)。
(4) 关闭连接:当应答结束后,web浏览器与web服务器必须断开,以保证其它web浏览器能够与web服务器建立连接。
二、java实现web服务器功能的程序设计
根据上述http协议的作用原理,实现get请求的web服务器程序的方法如下:
(1) 创建serversocket类对象,监听端口8080.这是为了区别于http的标准tcp/ip端口80而取的;
(2) 等待、接受客户机连接到端口8080,得到与客户机连接的socket;
(3) 创建与socket字相关联的输入流instream和输出流outstream;
(4) 从与socket关联的输入流instream中读取一行客户机提交的请求信息,请求信息的格式为:get 路径/文件名 http/1.0
(5) 从请求信息中获取请求类型。如果请求类型是get,则从请求信息中获取所访问的html文件名。没有html文件名时,则以index.html作为文件名;
(6) 如果html文件存在,则打开html文件,把http头信息和html文件内容通过socket传回给web浏览器,然后关闭文件。否则发送错误信息给web浏览器;
(7) 关闭与相应web浏览器连接的socket字。
下面的程序是根据上述方法编写的、可实现多线程的web服务器,以保证多个客户机能同时与该web服务器连接。
程序1:webserver.java文件
//webserver.java 用java编写web服务器
import java.io.*;
import java.net.*;
public class webserver {
public static void main(string args[]) {
int i=1, port=8080;
serversocket server=null;
socket client=null;
try {
server=new serversocket(port);
system.out.println("web server is listening on port "+server.getlocalport());
for (;;) {client=server.accept(); //接受客户机的连接请求
new connectionthread(client,i)。start();
i++;
}
} catch (exception e) {system.out.println(e);}
}
}
/* connnectionthread类完成与一个web浏览器的通信 */
class connectionthread extends thread {
socket client; //连接web浏览器的socket字
int counter; //计数器
public connectionthread(socket cl,int c) {
client=cl;
counter=c;
}
public void run() //线程体
{try {
string destip=client.getinetaddress()。tostring(); //客户机ip地址
int destport=client.getport(); //客户机端口号
system.out.println("connection "+counter+":connected to "+destip+" on port "+destport+".");
printstream outstream=new printstream(client.getoutputstream());
datainputstream instream=new datainputstream(client.getinputstream());
string inline=instream.readline(); //读取web浏览器提交的请求信息
system.out.println("received:"+inline);
if (getrequest(inline)) { //如果是get请求
string filename=getfilename(inline);
file file=new file(filename);
if (file.exists()) { //若文件存在,则将文件送给web浏览器
system.out.println(filename+" requested.");
outstream.println("http/1.0 200 ok");
outstream.println("mime_version:1.0");
outstream.println("content_type:text/html");
int len=(int)file.length();
outstream.println("content_length:"+len);
outstream.println("");
sendfile(outstream,file); //发送文件
outstream.flush();
} else { //文件不存在时
string notfound="
error 404-file not found
";outstream.println("http/1.0 404 no found");
outstream.println("content_type:text/html");
outstream.println("content_length:"+notfound.length()+2);
outstream.println("");
outstream.println(notfound);
outstream.flush();
}
}
long m1=1;
while (m1<11100000) {m1++;} //延时
client.close();
} catch (ioexception e) {
system.out.println("exception:"+e);
}
}
/* 获取请求类型是否为“get” */
boolean getrequest(string s) {
if (s.length()>0)
{if (s.substring(0,3)。equalsignorecase("get")) return true;
}
return false;
}
/* 获取要访问的文件名 */
string getfilename(string s) {
string f=s.substring(s.indexof(′ ′)+1);
f=f.substring(0,f.indexof(′ ′));
try {
if (f.charat(0)==′/′)
f=f.substring(1);
} catch (stringindexoutofboundsexception e) {
system.out.println("exception:"+e);
}
if (f.equals("")) f="index.html";
return f;
}
/*把指定文件发送给web浏览器 */
void sendfile(printstream outs,file file) {
try {
datainputstream in=new datainputstream(new fileinputstream(file));
int len=(int)file.length();
byte buf[]=new byte[len];
in.readfully(buf);
outs.write(buf,0,len);
outs.flush();
in.close();
} catch (exception e) {
system.out.println("error retrieving file.");
system.exit(1);
}
}
}
程序中的connectionthread线程子类用来分析一个web浏览器提交的请求,并将应答信息传回给web浏览器。其中,getrequest()方法用来检测客户的请求是否为“get”;getfilename(s)方法是从客户请求信息s中获取要访问的html文件名;sendfile()方法把指定文件内容通过socket传回给web浏览器。
对上述程序的getrequest()方法和相关部分作修改,也能对post请求进行处理。
三、运行实例
为了测试上述程序的正确性,将编译后的webserver.class、connectionthread.class和下面的index.html文件置于网络的某台主机的同一目录中(如:主机nt40srv的c:jweb目录)。
程序2:index.html文件
这是用java写出的web服务器主页
1998年8月28日
首先在该主机上用java命令运行webserver.class:
c:jweb>java webserver
然后在客户机运行浏览器软件,在url处输入webserver程序所属的url地址(如:http://nt40srv:8080/index.html),就在浏览器窗口显示出指定的html文档。
注意,不能缺省端口号8080,如缺省,则运行该主机的正常web服务器。
说明,不具备网络条件的可在安装了windows 95的单机上进行测试,方法是用localhost或127.0.0.1代替url地址的域名部分,即url地址为http://localhost:8080.
闽公网安备 35060202000074号