web服务器是如何工作的

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

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

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

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

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

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

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

支持jsp的web服务器 的原理

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

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

下图玩他的原理图

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

常用的web服务器

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

1.Apache HTTP Server

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

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

2.Tomact

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

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

研究一下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;j<i;j++){
receiveStr.append((char)buffer[j]);//将请求到的信息循环追加到receiverStr变量中
}
return getUri(requestStr.toString());
}
private String getUri(String receiveStr){
int index1,index2;
index1 = receiveStr.indexOf(' ');
if(index1 != -1){
index2 = receiveStr.indexOf(' ', index1+1);
if(index2>index1){
return receiveStr.substring(index1 +1,index2);
}
}
return null;
}
}

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

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

requestStr:GET/index.htm HTTP/1.1

Accept:*/*

Accept-Language:zh-cn

Accept-Encoding:gzip,deflate

User-Agent:Mozilla/4.0(compatiable;MSIE 6.0 ;Windows NT 5.1;SV1;

.NET CLR 1.1.4322;MAXTHON 2.0)

Host:localhost:8000

Connection: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"+
"<h1>File Not Found</h1>";
}
}catch(Exception e){
System.out.println(e.toString());
}finally {
if(fis != null){
fis.close();
}
}
}
}

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

http/1.1 200 OK

Content-Type:text/html

Content-Length:[要发送的数据长度]

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

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

闲来无聊,研究一下Web服务器 的源程序的更多相关文章

  1. 深入研究嵌入式web服务器的视频监控应用

    http://embed.chinaitlab.com/pc/776136.html uCLinux下,主要有3个Web Server:Httpd.Thttpd和BOA.Httpd是最简单的一个Web ...

  2. Windows下WEB服务器的选择与搭建

    本文主要基于支持perl的web服务器的选择. 一直基于web开发,服务器都是linux下使用webmin搭建的,惭愧的说一句,这么多年,也好好研究过WEB服务器,单从这个角度,是不是可以反应出web ...

  3. 高性能Web服务器Nginx的配置与部署研究(13)应用模块之Memcached模块+Proxy_Cache双层缓存模式

    通过<高性能Web服务器Nginx的配置与部署研究——(11)应用模块之Memcached模块的两大应用场景>一文,我们知道Nginx从Memcached读取数据的方式,如果命中,那么效率 ...

  4. 高性能Web服务器Nginx的配置与部署研究(7)核心模块之主模块的非测试常用指令

    1. error_log 含义:指定存储错误日志的文件 语法:error_log <file> [debug|info|notice|warn|error|crit] 缺省:${prefi ...

  5. ASP.NET Core技术研究-全面认识Web服务器Kestrel

    因为IIS不支持跨平台的原因,我们在升级到ASP.NET Core后,会接触到一个新的Web服务器Kestrel.相信大家刚接触这个Kestrel时,会有各种各样的疑问. 今天我们全面认识一下ASP. ...

  6. 高性能Web服务器Nginx的配置与部署研究(2)Nginx入门级配置与部署及“Hello World”

    1. Nginx 程序包 目前最新的开发版本时1.1.12: Linux/Unix:nginx-1.1.12.tar.gz Windows:nginx-1.1.12.zip 我们可以下载稳定版尝试: ...

  7. 高性能Web服务器Nginx的配置与部署研究(1)Nginx简介及入门示例

    概述 从这篇博文起,将带领读者们一起领略Nginx的强大. Nginx 是做什么用的?我相信很多朋友都已经使用过,如果你没有,那么你一定知道以下这些名称之一:Apache,Lighttpd,Tomca ...

  8. Ubuntu+Django+Nginx+uWSGI+Mysql搭建Python Web服务器

    Ubuntu+Django+Nginx+uWSGI+Mysql搭建Python Web服务器 闲着无聊的时候部署了一个Django项目玩,用vm虚拟机部署的. 准备工作 我使用的系统是Ubuntu16 ...

  9. 一不小心写了个WEB服务器

    开场 Web服务器是啥玩意? 是那个托管了我的网站的机器么? No,虽然那个也是服务器,但是我们今天要说的Web服务器主要是指像IIS这样一类的,用于处理request并返回response的工具,没 ...

随机推荐

  1. Apache执行Python脚本

    由于经常需要到服务器上执行些命令,有些命令懒得敲,就准备写点脚本直接浏览器调用就好了,比如这样: 因为线上有现成的Apache,就直接放它里面了,当然访问安全要设置,我似乎别的随笔里写了安全问题,这里 ...

  2. .NET Core 系列5 :使用 Nuget打包类库

    NuGet是个开源项目,项目包括 NuGet VS插件/NuGet Explorer/NuGetServer/NuGet命令行等项目,.NET Core项目完全使用Nuget 管理组件之间的依赖关系, ...

  3. 了解PHP中的Array数组和foreach

    1. 了解数组 PHP 中的数组实际上是一个有序映射.映射是一种把 values 关联到 keys 的类型.详细的解释可参见:PHP.net中的Array数组    . 2.例子:一般的数组 这里,我 ...

  4. jsp页面无法识别el表达式的解决方案

    今天在写一个springmvc的小demo时,碰到一个问题,在jsp页面中书写为${user.username}的表达式语言,在浏览器页面中仍然显示为${user.username},说明jsp根本不 ...

  5. 那些年【深入.NET平台和C#编程】

    一.深入.NET框架 1..NET框架具有两个组件:CLR(公共语言运行时)和FCL(框架类库),CLR是.NET框架的基础 2.框架核心类库: System.Collections.Generic: ...

  6. git常用命令(持续更新中)

    git常用命令(持续更新中) 本地仓库操作git int                                 初始化本地仓库git add .                       ...

  7. PC虚拟现实应用的性能分析与优化:从CPU角度切入

    如今,虚拟现实 (VR) 技术正日益受到欢迎,这主要得益于遵循摩尔定律的技术进步让这一全新体验在技术上成为可能.尽管虚拟现实能给用户带来身临其境般的超凡体验,但相比传统应用,其具有双目渲染.低延迟.高 ...

  8. BZOJ 1692: [Usaco2007 Dec]队列变换 [后缀数组 贪心]

    1692: [Usaco2007 Dec]队列变换 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1383  Solved: 582[Submit][St ...

  9. CYQ.Data V5 从入门到放弃ORM系列:教程 - MProc类使用

    MProc介绍 MProc:是一个用于执行SQL或存储过程的数据库操作类,它轻量高性能地类似于Dapper. MProc:它出现的场景很少,因为MAction自身就能处理掉90%-100%的数据操作( ...

  10. 快速构建App界面的框架(●'◡'●) -----SalutJs

    前言 卤煮在公司之初接触到的是一个微信APP应用.前端技术采用的是Backbone+zepto等小型JS类库.在项目开发之初,这类中小型的项目采用这两种库可以满足基本的需求.然而,随着迭代的更新和业务 ...