|
一、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.
|