HTTP初探

来源:互联网 发布:最近网络流行歌曲2017 编辑:程序博客网 时间:2024/04/29 20:58

Web客户端和服务器


浏览一个页面时( 比如http://www.oreilly.com/index.html), 浏览器会向服务器www.oreilly.com 发送一条HTTP 请求(参见上图)。服务器会去寻找所期望的对象(在这个例子中就是/index.html),如果成功,就将对象、对象类型、对象长度以及其他一些信息放在HTTP 响应中发送给客户端。

媒体类型

因特网上有数千种不同的数据类型,HTTP 仔细地给每种要通过Web 传输的对象都打上了名为MIME 类型(MIME type) 的数据格式标签。最初设计MIME(Multipurpose Internet Mail Extension,多用途因特网邮件扩展)是为了解决在不同的电子邮件系统之间搬移报文时存在的问题。MIME 在电子邮件系统中工作得非常好,因此HTTP 也采纳了它,用它来描述并标记多媒体内容。
Web 服务器会为所有HTTP 对象数据附加一个MIME 类型(参见图1-3)。当Web浏览器从服务器中取回一个对象时,会去查看相关的MIME 类型,看看它是否知道应该如何处理这个对象。大多数浏览器都可以处理数百种常见的对象类型:显示图片文件、解析并格式化HTML 文件、通过计算机声卡播放音频文件,或者运行外部插件软件来处理特殊格式的数据。


MIME 类型是一种文本标记,表示一种主要的对象类型和一个特定的子类型,中间由一条斜杠来分隔。


• HTML 格式的文本文档由 text/html 类型来标记。
• 普通的 ASCII 文本文档由 text/plain 类型来标记。
• JPEG 版本的图片为 image/jpeg 类型。
• GIF 格式的图片为 image/gif 类型。
• Apple 的 QuickTime 电影为 video/quicktime 类型。
• 微软的 PowerPoint 演示文件为 application/vnd.ms-powerpoint 类型。


常见的MIME 类型有数百个,实验性或用途有限的MIME 类型则更多。

报文

HTTP 报文是由一行一行的简单字符串组成的。HTTP 报文都是纯文本,不是二进
制代码,所以人们可以很方便地对其进行读写。


HTTP 报文包括以下三个部分:
• 起始行
报文的第一行就是起始行,在请求报文中用来说明要做些什么,在响应报文中说
明出现了什么情况。
• 首部字段
起始行后面有零个或多个首部字段。每个首部字段都包含一个名字和一个值,为
了便于解析,两者之间用冒号(:)来分隔。首部以一个空行结束。添加一个首
部字段和添加新行一样简单。
• 主体
空行之后就是可选的报文主体了,其中包含了所有类型的数据。请求主体中包括
了要发送给Web 服务器的数据;响应主体中装载了要返回给客户端的数据。起
始行和首部都是文本形式且都是结构化的,而主体则不同,主体中可以包含任意
的二进制数据(比如图片、视频、音轨、软件程序)。当然,主体中也可以包含
文本。

简单的报文实例

下图显示了可能会作为某个简单事务的一部分发送的HTTP 报文。浏览器请求资源http://www.joes-hardware.com/tools.html。
在下图中,浏览器发送了一条HTTP 请求报文。这条请求的起始行中有一个GET命令,且本地资源为/tools.html。这条请求说明它使用的是1.0 版的HTTP 协议。请求报文没有主体,因为从服务器上GET 一个简单的文档不需要请求数据。
服务器会回送一条HTTP 响应报文。这条响应中包含了HTTP 的版本号(HTTP/1.0)、一个成功状态码(200)、一个描述性的原因短语(OK), 以及一块响应首部字段,在所有这些内容之后跟着包含了所请求文档的响应主体。Content-Length首部说明了响应主体的长度,Content-Type 首部说明了文档的MIME 类型。


HTTP的基础TCP/IP

我们来讨论一下报文是如何通过传输控制协议(Transmission Control Protocol,TCP)连接从一个地方搬移到另一个地方去的。

HTTP 是个应用层协议。HTTP 无需操心网络通信的具体细节;它把联网的细节都交给了通用、可靠的因特网传输协议TCP/IP。


TCP 提供了:
• 无差错的数据传输;
• 按序传输(数据总是会按照发送的顺序到达);
• 未分段的数据流(可以在任意时刻以任意尺寸将数据发送出去)。


因特网自身就是基于TCP/IP 的,TCP/IP 是全世界的计算机和网络设备常用的层次化分组交换网络协议集。TCP/IP 隐藏了各种网络和硬件的特点及弱点,使各种类型的计算机和网络都能够进行可靠地通信。
只要建立了TCP 连接,客户端和服务器之间的报文交换就不会丢失、不会被破坏,也不会在接收时出现错序了。


用网络术语来说,HTTP 协议位于TCP 的上层。HTTP 使用TCP 来传输其报文数
据。与之类似,TCP 则位于IP 的上层



在HTTP 客户端向服务器发送报文之前,需要用网际协议(Internet Protocol,IP)地址和端口号在客户端和服务器之间建立一条TCP/IP 连接。


建立一条TCP 连接的过程与给公司办公室的某个人打电话的过程类似。首先,要拨打公司的电话号码。这样就能进入正确的机构了。其次,拨打要联系的那个人的分机号。


在TCP 中,你需要知道服务器的IP 地址,以及与服务器上运行的特定软件相关的TCP 端口号。


这就行了,但最初怎么获得HTTP 服务器的IP 地址和端口号呢?当然是通过URL了!我们前面曾提到过,URL 就是资源的地址,所以自然能够为我们提供存储资源的机器的IP 地址。我们来看几个URL:

http://207.200.83.29:80/index.html
http://www.netscape.com:80/index.html
http://www.netscape.com/index.html

第一个URL 使用了机器的IP 地址,207.200.83.29 以及端口号80。
第二个URL 没有使用数字形式的IP 地址,它使用的是文本形式的域名,或者称为主机名(www.netscape.com)。主机名就是IP 地址比较人性化的别称。可以通过一种称为域名服务(Domain Name Service,DNS)的机制方便地将主机名转换为IP地址,这样所有问题就都解决了。
最后一个URL 没有端口号。HTTP 的URL 中没有端口号时,可以假设默认端口号是80。
有了IP 地址和端口号,客户端就可以很方便地通过TCP/IP 进行通信了。下图显示了浏览器是怎样通过HTTP 显示位于远端服务器中的某个简单HTML 资源的。


步骤如下:
(a) 浏览器从URL 中解析出服务器的主机名;
(b) 浏览器将服务器的主机名转换成服务器的IP 地址;
(c) 浏览器将端口号(如果有的话)从URL 中解析出来;
(d) 浏览器建立一条与Web 服务器的TCP 连接;
(e) 浏览器向服务器发送一条HTTP 请求报文;
(f) 服务器向浏览器回送一条HTTP 响应报文;
(g) 关闭连接,浏览器显示文档。


使用Telnet与TCP对话

由于HTTP 使用了TCP/IP 传输协议,而且它是基于文本的,没有使用那些难以理解的二进制格式,因此很容易直接与Web 服务器进行对话。
Telnet 程序可以将键盘连接到某个目标TCP 端口,并将此TCP 端口的输出回送到显示屏上。Telnet 常用于远程终端会话,但它几乎可以连接所有的TCP 服务器,包括HTTP 服务器。
可以通过Telnet 程序直接与Web 服务器进行对话。通过Telnet 可以打开一条到某台机器上某个端口的TCP 连接,然后直接向那个端口输入一些字符。Web 服务器会将Telnet 程序作为一个Web 客户端来处理,所有回送给TCP 连接的数据都会显示在屏幕上。
我们用Telnet 与一个实际的Web 服务器进行交互。我们要用Telnet 获取URLhttp://www.joes-hardware.com:80/tools.html 所指向的文档(你可以自己尝试一下这个实例)。
我们来看看会发生什么情况。
首先,查找www.joes-hardware.com • 的 IP 地址,打开一条到那台机器端口 80 的TCP 连接。Telnet 会为我们完成那些“跑腿儿”的工作。
• 一旦打开了 TCP 连接,就要输入 HTTP 请求了。
• 请求结束(由一个空行表示)之后,服务器会在一条 HTTP 响应中将内容回送并关闭连接。
下例显示了对http://www.joes-hardware.com:80/tools.html 的HTTP 请求实例。我们输入的内容用粗体字表示。


Telnet 会查找主机名并打开一条连接,连接到在www.joes-hardware.com 的端口80上监听的Web 服务器。这条命令之后的三行内容是Telnet 的输出,告诉我们它已经建立了连接。
然后我们输入最基本的请求命令GET/tools.html HTTP/1.1,发送一个提供了源端主机名的Host 首部,后面跟上一个空行,请求从服务器www.joes-hardware.com上获取资源tools.html。随后,服务器会以一个响应行、几个响应首部、一个空行和最后面的HTML 文档主体来应答。
要明确的是,Telnet 可以很好地模拟HTTP 客户端,但不能作为服务器使用。而且对Telnet 做脚本自动化是很繁琐乏味的。


HTTP协议版本

现在使用的HTTP 协议有几个版本。HTTP 应用程序要尽量强健地处理各种不同的HTTP 协议变体。目前仍在使用的版本如下。


• HTTP/0.9
HTTP 的1991 原型版本称为HTTP/0.9。这个协议有很多严重的设计缺陷,只应该用于与老客户端的交互。HTTP/0.9 只支持GET 方法,不支持多媒体内容的MIME 类型、各种HTTP 首部,或者版本号。HTTP/0.9 定义的初衷是为了获取简单的HTML 对象,它很快就被HTTP/1.0 取代了。


• HTTP/1.0
1.0 是第一个得到广泛使用的HTTP 版本。HTTP/1.0 添加了版本号、各种HTTP首部、一些额外的方法,以及对多媒体对象的处理。HTTP/1.0 使得包含生动图片的Web 页面和交互式表格成为可能,而这些页面和表格促使万维网为人们广泛地接受。这个规范从未得到良好地说明。在这个HTTP 协议的商业演进和学术研究都在快速进行的时代,它集合了一系列的最佳实践。


• HTTP/1.0+
在20 世纪90 年代中叶,很多流行的Web 客户端和服务器都在飞快地向HTTP中添加各种特性,以满足快速扩张且在商业上十分成功的万维网的需要。其中很多特性,包括持久的keep-alive 连接、虚拟主机支持,以及代理连接支持都被加入到HTTP 之中,并成为非官方的事实标准。这种非正式的HTTP 扩展版本通常称为HTTP/1.0+。


• HTTP/1.1
HTTP/1.1 重点关注的是校正HTTP 设计中的结构性缺陷,明确语义,引入重要的性能优化措施,并删除一些不好的特性。HTTP/1.1 还包含了对20 世纪90 年代末正在发展中的更复杂的Web 应用程序和部署方式的支持。HTTP/1.1 是当前使用的HTTP 版本。


• HTTP-NG(又名 HTTP/2.0)
HTTP-NG 是HTTP/1.1 后继结构的原型建议,它重点关注的是性能的大幅优化,以及更强大的服务逻辑远程执行框架。HTTP-NG 的研究工作终止于1998 年,编写本书时,还没有任何要用此建议取代HTTP/1.1 的推广计划。


TCP连接

世界上几乎所有的HTTP 通信都是由TCP/IP 承载的,TCP/IP 是全球计算机及网络设备都在使用的一种常用的分组交换网络分层协议集。客户端应用程序可以打开一条TCP/IP 连接,连接到可能运行在世界任何地方的服务器应用程序。一旦连接建立起来了,在客户端和服务器的计算机之间交换的报文就永远不会丢失、受损或失序。


TCP的可靠数据管道

HTTP 连接实际上就是TCP 连接和一些使用连接的规则。TCP 连接是因特网上的可靠连接。要想正确、快速地发送数据,就需要了解TCP 的一些基本知识。

TCP 为HTTP 提供了一条可靠的比特传输管道。从TCP 连接一端填入的字节会从另一端以原有的顺序、正确地传送出来


TCP流是分段的、由IP分组传送

TCP 的数据是通过名为IP 分组(或IP 数据报)的小数据块来发送的。

HTTP 要传送一条报文时,会以流的形式将报文数据的内容通过一条打开的TCP 连接按序传输。TCP 收到数据流之后,会将数据流砍成被称作段的小数据块,并将段封装在IP 分组中,通过因特网进行传输。所有这些工作都是TCP/
IP 软件来处理的,HTTP 程序员什么都看不到。


每个TCP 段都是由IP 分组承载,从一个IP 地址发送到另一个IP 地址的。每个IP分组中都包括:

• 一个 IP 分组首部(通常为 20 字节);
• 一个 TCP 段首部(通常为 20 字节);
• 一个 TCP 数据块(0 个或多个字节)。


IP 首部包含了源和目的IP 地址、长度和其他一些标记。TCP 段的首部包含了TCP端口号、TCP 控制标记,以及用于数据排序和完整性检查的一些数字值。


保持TCP连接的正确运行

在任意时刻计算机都可以有几条TCP 连接处于打开状态。TCP 是通过端口号来保持所有这些连接的正确运行的。


端口号和雇员使用的电话分机号很类似。就像公司的总机号码能将你接到前台,而分机号可以将你接到正确的雇员位置一样,IP 地址可以将你连接到正确的计算机,而端口号则可以将你连接到正确的应用程序上去。TCP 连接是通过4 个值来识别的:


< 源IP 地址、源端口号、目的IP 地址、目的端口号>


这4 个值一起唯一地定义了一条连接。两条不同的TCP 连接不能拥有4 个完全相同的地址组件值(但不同连接的部分组件可以拥有相同的值)


在下图中,有4 条连接:A、B、C 和D。下表列出了每个端口的相关信息。




注意,有些连接共享了相同的目的端口号(C 和D 都使用目的端口号80)。有些连接使用了相同的源IP 地址(B 和C)。有些使用了相同的目的IP 地址(A 和B,C和D)。但没有两个不同连接所有的4 个值都一样。


浏览器与SOCKET服务端的对话

socket server端代码:


package com.shmec.socket;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;


public class SocketServer {
    public static void main(String[] args) throws IOException {  
        ServerSocket server = new ServerSocket(80);
        System.out.println("server:"+InetAddress.getLocalHost().getHostAddress()+" is already...");
        Socket client = server.accept();        
        BufferedReader in = new BufferedReader(new InputStreamReader(  
                client.getInputStream()));  
        PrintWriter out = new PrintWriter(client.getOutputStream());  
        while (true) {  
            String str = in.readLine();  
            System.out.println(str);
              
            if (str.equals("")){
            StringBuilder sb = new StringBuilder();
                sb.append("HTTP/1.1 200 OK").append("\n")
                .append("Content-Type: text/html").append("\n")
                .append("Content-Length: 433").append("\n")
                .append("").append("\n")
                .append("<HTML><HEAD><TITLE>Joe's Tools</TITLE></HEAD><BODY><H1>Tools Page</H1><H2>Hammers</H2></BODY></HTML>");
                System.out.println();
                System.out.println(sb.toString());
                out.println(sb.toString());  
                out.flush();
                break;
            }else if(str.equals("end")){
            break;
            }
               
        }  
        client.close();  
    }
}


服务端起来后,使用浏览器访问:http://localhost/


0 0
原创粉丝点击