分享

闲来无聊,研究一下Web服务器 的源程序

 youxd 2017-01-02

web服务器是如何工作的

1989年的夏天,蒂姆.博纳斯-李开发了世界上第一个web服务器和web客户机。这个浏览器程序是一个简单的电话号码查询软件。最初的web服务器程序就是一个利用浏览器和web服务器软件之间的联系,将存储在硬盘上的文件传递给远程的读者。

web服务器软件主要是提供web服务的软件,为浏览器提供http数据的支持。

闲来无聊,研究一下Web服务器 的源程序

它无非就是把硬盘上的文件 以http数据流 的形式提供给web服务器,这就是它的基本用途。这个基本用途就是作为web服务器软件的发明人蒂姆.博纳斯-李发明web服务器的初衷。

需要传递的硬盘上 的文件 的格式是html格式的标记性语言的文件。web服务器软件在接受到浏览器的访问请求的时候,将直接不加任何修改的将这个html文件传递到远程浏览器端,传输协议是TCP的HTTP协议。

再看下图,深入了解他的原理。

闲来无聊,研究一下Web服务器 的源程序

这是一个最初的web服务器软件 的原理图,也是一个支持html格式文件服务 的所以web服务器 的原理图,即使是最著名 的Apache HTTP Server也是这个原理。

所谓的静态页面是指本地文件直接被web服务器取得的这种web页面。而想Asp,jsp,php这样的所谓动态页面是怎么个原理呢?

支持jsp的web服务器 的原理

动态页面 的web服务器和静态页面的web服务器之间仅有一点的区别,就是在本地端得到html格式信息的方法不是直接从文件中读取,而是从程序电脑生成信息中获取而已。

那么,支持jsp的动态 的web服务器的原理又是什么养的呢?其实就是多了一个将jsp文件转换成java文件并且编译 的过程,然后运行那个被编译的Class文件,从而时期得到要返回给了浏览器的格式信息,然后将其返回给远端的浏览器。

下图玩他的原理图

大家估计都要已经看出来了,与返回静态页面的区别是,返回的信息是由过程生成的。其实,原理很简单,无非就是读文件发出去而已。

常用的网表服务器

前面介绍的就是web服务器的 工作原理,java程序猿应该对下面的这些软件做到非常熟悉

1.Apache HTTP Server

Apache也许是时间最久也是最流的 http服务器软件。快速、可靠,通过简单的API扩展,Perl/Python解释器可悲编译到服务器当中,完全免费,源代码开放。

官方的站点为http://httpd./.

2.Tomact

是目前业界被最广泛认可 的一个web服务器,他是Java Servlet2.2和Java Server Pages1.1技术的标准实现,是基于Apache许可证下的开发 是自由软件,由Jakarta项目组开发,

官方站点是http://tomcat./

研究一下web服务器的源程序

既然web服务器的原理如此简单,那就手动自己开一个试试吧。

1.步骤一、确定用TCP作为服务传输协议

package yxh;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;/** * * @author Baron * @version 创建时间:2017年1月2日 * @Dsecription 确定用TCP 作为服务传输协议,首先做一个main函数,建立Socket ,并用一个“死循环” 的形式* 监听指定端口。 */public class HttpServer { public static String ROOT = './wwwroot'; ///默认root文件夹 public static String defaultPage = 'index.html'; //默认文件的文件名 public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(8000); while(true) { //阻塞,等待浏览器的连接 Socket sk = server.accept; System.out.println('Accepting Connection ...\n'); //启动服务线程 new HttpThread(sk).start; } }}

首先做一个main函数,简历一个Socket并且用一个“死循环’”的形式监听指定端口。程序如下

2.步骤2.实现一个多线程的 程序,用于处理每一个客户的请求。程序如下。

package yxh;import java.io.*;import java.net.Socket;/** * * @author Baron * @version 创建时间:2017年1月2日 * @Dsecription 实现一个多线程,处理每个用户的请求 */public class HttpThread extends Thread { private Socket sock; HttpThread(Socket socktmp){ this.sock = socktmp; } public void run { InputStream ins = null; OutputStream outs = null; try{ ins = sock.getInputStream; outs= sock.getOutputStream; Receive rcv = new Receive(ins); String sURL = rcv.parse; //用Receive 类取得浏览器发过来 的URL请求 if(sURL.equals('/')){ sURL = HttpServer.defaultPage;// 如果没有指定文件,那么给传过来的URL加上默认的文件名 } Answer ans = new Answer(outs); ans.Send(sURL);//再将URL执行的文件用Answer类的send方法放回给浏览器 }catch(IOException e){ System.out.println(e.toString); } finally{ //最后调用那些类的close方法释放资源 try{ if(ins != null) ins.close; if(outs != null) outs.close; if(sock != null) sock.close; }catch(IOException e){} } }}

3.步骤3.如何取得浏览器传来的URL

现在实现的这个类是Receive,用这个类u取得了来自浏览器的字符串。程序如下。

package yxh;import java.io.IOException;import java.io.InputStream;/** * * @author Baron * @version 创建时间:2017年1月2日 * @Dsecription 取得浏览器传过来的URL 字符串 */public class Receive { InputStream in = null; public Receive(InputStream input){ this.in = input; } //这个方法 的目的是将URL 请求的文件返回 public String parse{ StringBuffer receiveStr = new StringBuffer(2048);//这个变量就是实际从浏览器取得的请求数据流 int i; byte buffer = new byte[2048]; try{ i = in.read(buffer);//从Socket读出数据 }catch(IOException e){ i= -1; } for(int j=0;jindex1){ return receiveStr.substring(index1 +1,index2); } } return null; }}

下面来解释getUri这个方法,大家一定觉得奇怪,这个方法从两个空格之间取得了URL的文件名,这是怎么回事?

其实,只要把receiveStr打印出来就可以了。下面来看看浏览器发过来的 请求是什么字符串,请求字符串如下。

requestStr:GET/index.htm HTTP/1.1Accept:*/*Accept-Language:zh-cnAccept-Encoding:gzip,deflateUser-Agent:Mozilla/4.0(compatiable;MSIE 6.0 ;Windows NT 5.1;SV1;.NET CLR 1.1.4322;MAXTHON 2.0)Host:localhost:8000Connection:Keep-Alive

那么在浏览器里面请求的 URL是这样的

http://localhost:8000/index.htm

这时候可以发现,出现在第一个“空格”和第二个“空格”之间包围的字符串就是“、index.htm”,这就是要取得的字符串。好了,这下可以明白,为什么取两个空格之间的东西了吧!

那么,打印出来的 这个receiveStr其实就是按照http协议发过来的请求数据流,现在需要做的就是格局http协议将浏览器希望得到的内容返回出去。

4.步骤4.返回http数据流

返回的数据流的要求是:按照http 的要求返回请求文件。程序如下。

package yxh;import java.io.*;/** * * @author Baron * @version 2017年1月2日 * @Dsecription 返回Http 数据流 */public class Answer { OutputStream out = null; public Answer(OutputStream output){ this.out = output; } public void Send(String pagefile) throws IOException{ //这个方法是关键,其目的是返回HTTP数据流 byte bytes = new byte[2048]; FileInputStream fis = null; try{ //读取指定的文件内容 File file = new File(HttpServer.ROOT,pagefile); if(file.exists){ fis = new FileInputStream(file); int ch = fis.read(bytes, 0, 2048); @SuppressWarnings('deprecation') String sBody = new String(bytes,0); //返回 的信息是在文件的内容的前面加上Http协议的格式内容 String sendMessage = 'HTTP/1.1 200 OK\r\n'+ 'Content-Type:text/html\r\n'+ 'Content-Length:'+ch+'\r\n'+ '\r\n'+sBody; //输出文件 out.write(sendMessage.getBytes); }else{ //文件不存在的话,返回一个Http协议的格式内容 @SuppressWarnings('unused') String errorMessage = 'HTTP/1.1 404 File Not Found\r\n'+ 'Content-Type:text/html\r\n'+ 'Content-Length:23\r\n'+ '\r\n'+ '

File Not Found

'; } }catch(Exception e){ System.out.println(e.toString); }finally { if(fis != null){ fis.close; } } }}

这回完全清楚了吧!web服务器正真返回给浏览器 的内容是:在http文件内容的前面加上协议内容格式信息。这个格式信息如下。

http/1.1 200 OKContent-Type:text/htmlContent-Length:[要发送的数据长度]

之所以在浏览器这边可以看到不同的字体的颜色等信息,完全是浏览器自己对html标记性语言解析的结果。

有兴趣的盆友如果想做一个更加强大更加完整的web服务器软件的话,可以更深入的研究http协议。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多