该层定义了比特作为信号在信道上发送时相关的电气、时序和其他接口。
物理层是构建网络的基础。物理信道的不同特性决定了其传输性能的不同(比如吞吐量、延迟和误码率).
本章节首先从数据传输的理论分析出发,探讨决定信道传输的自然局限。并给出三类传输介质:
然后,讨论数字调制解调技术,主要解决如何把模拟信号转换成数字比特以及将数字比特还原成模拟信号。在此基础上,引入多路复用方案,探讨如何在同一个传输介质上同时进行多个会话而彼此不被干扰。
最终,重点关注三个被广泛应用于计算机广域网的通信系统实例:
傅里叶分析:
19世纪早期,法国科学家傅里叶证明了:任何一个行为合理的周期为T的函数 g(t) ,都可以表示成用正弦函数和余弦函数组成的无穷级数:
一般情况下对导线而言,在0大某个频率 fc 的这段范围内,振幅在传输过程中不会衰减,而在此截止频率 fc 之上,的所有频率的振幅都将有不同成都的减弱,这段在传输过程中振幅不会明细减弱的频率宽度称为宽带。
实际上,截止频率并没有那么尖锐,所以,通常引用的带宽是指从0到使得接受能力保留一半的那个频率位置。
物理层的作用是将比特从一台机器传输到另一台机器。实际传输所用的物理介质可以有多种选择。大致可以分为引导性介质(有线介质,铜线或光纤之类)和非引导性介质(无线介质,无线电,卫星等)。
双绞线由两根相互绝缘的铜线组成,
该层内容涉及两台机器实现可靠有效的完整信息块(称为帧)通信的一些算法,而不像物理层那样只关注单个比特传输。
数据链路层使用物理层提供的服务在通信信道上发送和接收比特。功能包括:
如图所示,为了实现上述的目标,数据链路层从网络层获得数据包,然后将这些数据包封装成帧(frame),以便传输。每个帧包含帧头、有效载荷(数据)、帧尾。数据链路层的核心就是对帧进行管理。
数据链路层可以设计成向上提供各种不同的服务。可以分为以下三种:
对于数据链路层,通常是把从物理层获得的比特流拆分成多个离散的帧。
这里介绍了四种成帧方法:
1. 字节计数法: 利用头部中的第一个字段来标识该帧中的字节数。如图。但是采用这种方法,计数值可能因为一个传输错误而被弄混而导致接收方失去同步,无法找到下一帧的正确起始位置。
2. 字节填充的标志字节法:该方法考虑到出错之后,重新同步的问题,让每个帧用一些特殊的字节作为开始和结束。这些特殊字节通常都相同,称为特殊字节(flag byte),作为帧的起始和结束分界符。当标志字节出现在数据中时,可以通过在前面加一个特殊的转义字节(ESC)来进行区分。如果接收方丢失了同步,它只需要搜索两个标志字节就能找到当前帧的结束和下一帧的开始位置。
3. 比特填充的标志字节法:每个帧的开始和结束由一个特殊的比特模式,0111 1110(0x7E)标记。这是一个标记字节。每当发送方的数据链路层在数据中遇到连续五个1时,它边自动的在输出的比特流中填入一个比特0.(USB即通用串行总线,便采用了这种比特填充技术。)。当接收方看到5个连续入境比特,并且后面紧跟一个比特0,他就自动删除比特0.
4. 物理层编码的违禁法。
通过差错控制,如何确保所有的帧最终都被传递给目标机器的网络层,并且保持正确的顺序。
对差错进行控制有两种基本策略:
1. 纠错码:在每一个被发送的数据块中包含足够多的冗余信息以便接收方能据此推断出被发送的数据室什么
2. 检错码:在每个被发送的数据块中加入冗余信息,但是这些信息只能让接收方推断出是否发生了错误(而推断不出哪个发生了错误),然后接收方可以请求发送重传。
上面的四种方法都是通过将冗余信息加入到待发送的信息中。一个帧由m个数据位(信息)和r个冗余位(校验)组成。
令数据块的总长度为n(即n=m+r),我们将此描述为(n,m)码, 一个包含了数据位和校验位的n位单元称为n位码字.
码率:则定义为码字中不包含冗余部分所占的比例,用m/n表示。
首先,看一下传输错误是什么样的。
给定两个被发送或接收的码字,比如说”1000 1001”和”1011 0001”, 为确定两个码字有多少个不同位,只需要XOR两个码字,并计算结果中1的个数。
两个码字中不相同的个数称为海明距离,它的意义在于,如果两个码字的海明距离为d,则需要d个1位错误才能将一个码字转变成另一个码字。
块码的检错和纠错特性跟它的海明距离有关,为了可靠的监测d个错误,需要一个距离为d+1的编码方案。为了纠正d个错误,需要一个距离为2d+1的编码方案。
网络层关注的是如何将源端数据包送到接收方。为了将数据包送到接收方,可能沿途要经过许多跳(hop)中间路由器。
为了实现这个目标,网络层必须知道网络拓扑结构(即所有路由器和链路的集合),并从中选择出适当的路径。即使是大型网络也要选出一条好路径。同时网络层还必须仔细选择路由器,避免某些通信线路和路由器负载过重,而其他线路和路由器空闲。
在介绍网络层细节之前,有必要说明网络层协议运行的上下文。如图,网络中最主要的组件是网络服务提供商(ISP)的设备(通过传输线路连接的路由器)和客户端设备。图中,ISP的设备位于阴影椭圆内,而客户端位于椭圆之外。主机H1直接连接到ISP的路由器A,这或许是一台家用计算机,通过DSL调制解调器接入而H2则位于一个局域网内,这可能是一个办公室以太网,其上还有台路由器F,客户端拥有这台路由器并负责其运行。路由器F通过一条租用线路连接到ISP的设备上。
这种网络配置的使用方式如下所述,如果一台主机要发送一个数据包,它就将数据包传输给最近的路由器,路由器可能在它自己的LAN上,也可能在一条通向ISP的点到点链路上。在该数据包到达路由器,并且路由器的链路层完成了对它校验和验证之后,它先被存储在路由器上,然后沿着路径被转发到下一个路由器,直至到达目标主机。这种机制就是存储-转发数据包交换。
网络层通过
如果网络层提供的是无连接的服务,那么所有的数据包都被独立的注入到网络中,并且每个数据包独立于路由,不需要建立任何设置。在这种情况下,数据包通常被称为数据报(datagram),对应的网络称为数据报网络。
如果网络层使用了面向连接的服务,那么在发送数据包之前,必须首先建立起一条从源路由器到目标路由器之间的路径。这个连接称为虚电路,它类似于电话系统中建立的物理电路,对应的网络称为虚电路网络。
路由算法是网络层软件的一部分,它负责确定一个入境数据包应该被发送到那一条输出线路上。如果网络内部使用了数据报,那么路由器必须针对每一个到达的数据包重新选择路径,因为上一次选择了路径之后,最佳路径可能已经发生了变化。如果网络内部使用虚电路,那么只有当监理一条新的虚电路时,才需要做路由决策。
路由算法分为两大类:非自适应算法和自适应算法。
在实现路由算法时,每个路由器必须根据本地知识而不是网络的全貌做决策。一个简单的本地技术是泛洪(flooding),这种技术将每一个入境数据包发送到除了该数据包到达的那条线路以外的每条出境线路。
泛洪会差生大量重复数据包。为了印制泛洪过程产生无限多的数据包,可以在每个数据包的头中设置一个跳计数器,每经过一跳,该计数器减一,当计数器到达0时,丢弃该包。
每个路由器维护一张表,表中列出了当前已知的到每个目标的最佳距离,以及所使用的链路。这些表通过邻居之间相互交换信息而不断被更新,最终每个路由器都了解到达每个目的地的最佳链路
由于当网络拓扑结构发生变化后,距离矢量路由算法需要太长时间才能收敛到稳定状态(无穷计数问题)。因此距离矢量路由算法被链路状态路由算法代替。如今,该算法的变种算法IS-IS或者OSPF已经成为大型网络或Internet应用最为广泛的路由算法。
链路状态路由算法可以用五个部分描述,每一个路由器必须完成以下工作:
1. 发现它的邻居节点,并了解其网络地址
2. 设置到每个邻居节点的距离或成本度量值
3. 构造一个包含所有刚刚获知的链路信息包
4. 将这个包发送给所有其他的路由器,并接收来自所有其他路由器的信息包
5. 计算出到每个其他路由器的最短路径
随着网络规模的增长,路由器的路由表也成比例的增长。不断增长的路由表不仅消耗路由器内存,而且还需要更多的CPU时间来扫描路由表以及更多的带宽来发送有关的状态报告。当网络增长到一定时可能会达到某种程度,此时每个路由器不太可能再为其他每一个路由器维护一个表项。所以路由不得不分层次进行。
在采用了分成路由之后,路由器被划分成区域,每个路由器知道如何将数据包路由到自己所在的区域内的目标地址,但是对于其他区域的内部结构毫不知情。
网络中存在太多的数据包时,会导致数据包被延迟和丢失,从而降低了传输性能,这种情况称为拥塞。
网络层和传输层共同承担着处理拥塞的责任。
从一个源端发到一个接收方的数据包流称为一个流。在面向连接的网络中,一个流或许是一个连接上的全部数据包,而在无连接网络中,一个流是从一个进程发到另一个进程的所有数据包。
每个流的需求可用四个主要参数来表示:
带宽、延迟、抖动、和丢失。
这些参数决定一个流要求的服务质量(QoS, Quality of Service)
NAT的基本思想是ISP为每个家庭或每个公司分配一个IP地址(或者最多分配少了的IP地址),用这个IP地址来传输Internet流量。在客户网络内部,每台计算机有唯一的IP地址,该地址用来路由内部流量。
当一个数据包需要离开客户网络,发向其他ISP时,它必须执行一个地址转换,把唯一的内部IP地址转换成那个共享的公共IP地址。
这种地址使用了IP地址的三个范围,这些地址已经被声明为私有化。
路由器严密监控Internet的操作,当路由器在处理一个数据包的过程中发生了意外,可通过Internet控制消息协议想数据包的源端报告有关事件。
已经定义的ICMP消息类型大约有10多种,每一种ICMP消息类型都被封装在一个IP数据包中。
消息类型 | 描述 |
---|---|
目的地不可达 | 数据包无法传递 |
超时 | TTL字段减为0 |
参数问题 | 无效的头字段 |
源抑制 | 抑制包 |
重定向 | 告知路由器有关地理信息 |
回显和回显应答 | 检查一台机器是否还活着 |
请求/应答时间戳 | 与回显一样,但还要求时间戳 |
路由器通告/恳求 | 发现附近的路由器 |
传输层架构在网络层提供的服务之上,把数据传递服务从两台计算机之间扩展到两台计算机的进程之间。并且服务所需的可靠性程度独立于当前使用的物理网络。传输层为应用层使用网络提供了抽象的模式。
本章涉及的内容包括传输层的服务和API设计的选择,其中包括可靠性、连接和拥塞控制,协议和性能等问题的解决。
与网络层提供面向连接和无连接两种服务一样,传输层的服务类型也分为两种。面向连接的传输服务在许多方面与面向连接的网络服务类似,两者都要经历连接建立、数据传输和连接释放三个阶段。另外,无连接的传输服务与无连接的网络服务也极为相似。
于是,既然传输层服务与网络层服务如此相似,为什么还需要设立两个独立的层?
原因是因为传输层的代码完全运行在用户的机器上,但是网络层代码主要运行在由运营商操作的路由器上(至少对广域网是如此)。如果网络层提供的服务不够用,怎么办?如果它频繁的丢失数据包怎么办?如果路由器时常崩溃怎么办?
用户对网络层没有真正的控制权,因为他们不拥有路由器,所以不能用更好的路由器或者在数据链路层上用更好的错误处理机制来解决服务太差的问题。唯一可能是在网络层之上再加一层,由该层来提高网络的服务质量。
本质上,由于传输层的存在,是的传输服务有可能比网络服务更加可靠。而且传输服务原语可以通过调用库程序来实现,从而使得这些原语独立于网络服务原语。
正是有了传输层,应用程序员才可以按照一组标准的原语来编写代码,并且程序可以运行在各种各样的网络上,他们不需要处理不同的网络接口,也不用担心传输的可靠性。
为了了解传输服务的基本面貌,下表给出了5个原语:
原语 | 发出的包 | 含义 |
---|---|---|
LISTEN | 无 | 阻塞,知道某个进程视图与之连接 |
CONNECT | CONNECTION REQ | 主动尝试建立连接 |
SEND | DATA | 发送信息 |
RECEIVE | 无 | 阻塞,知道到达一个DATA包 |
DISCONNECT | DISCONNECTION REQ | 请求释放连接 |
用户数据报协议(UDP, User Datagram Protocol),为应用程序提供了一种无需建立连接就可以发送封装IP数据报的方法.(RFC768描述了UDP)。
UDP传输的段由8个字节的头和有效载荷字段构成。
DNS的本质是一种层次的、基于域的命名方案,并且用一个分布式的数据库系统加以实现。
它的主要用途是将主机名映射成IP地址。应用程序调用一个名为解析器的库程序,并将名字作为参数传递给此程序(比如gethostbyname()就是一个解析器函数)。解析器向本地DNS服务器发送一个包含该名字的请求报文,本地DNS服务器查询该名字,并返回一个包含该名字对应IP地址的响应报文给解析器,然后解析器再将IP地址返回给调用方。查询报文和响应报文都作为UDP数据包发送。
对于Internet,命名层次结构的顶级由一个专门组织负责管理。该组织名为Internet名字与数字地址分配结构(ICANN, Internet Corporation for Assigned Names and Numbers).
从概念上讲,Internet被划分为超过250个顶级域名(top-level domains),其中每个域包含许多主机,这些域又被进一步划分成子域,可以通过树形结构来表示。如下图所示
顶级域名分为两种类型:通用的和国家或地区的。
电子邮件系统的体系结构如图所示,它包括两类子系统:用户代理和邮件传输代理。
* 用户代理:是一个程序,用户通过它与电子邮件系统交互。
* 邮件传输代理:通常是系统进程。他们运行在邮件服务器机器的后台,并始终保持运行状态。它们的工作时通过系统自动将电子邮件从发送端移动到收件人,采用的协议是简单邮件传输协议(SMTP, Simple Mail Transfer Protocol)
电子邮件系统的一个关键思想是将信封(envelope)与邮件内容区分开来。信封将消息封装成邮件,它包含了传输消息所需要的所有信息,例如目标地址、优先级和安全级别,所有这些都有别于消息本身。消息传输代理根据信封进行路由。
信封内的消息由两部分组成:邮件头(header)和邮件体(body)。邮件头包含用户代理所需的控制信息。邮件体则完全提供给收件人,代理和邮件传输代理都不在意邮件体包含了什么信息。
用户代理是一个程序。
用户代理发出的邮件必须设置成邮件传输代理能处理的标准格式。
早期电子邮件只能由文本消息组成,这些消息用英文书写并且以ASCII码的形式表示。
多用途Internet邮件扩展(MIME, Multipurpose Internet Mail Extensions)就是为了解决包含非文本的邮件(音频,图像或二进制文档等)。
MIME定义了5种新的邮件头。
邮件头 | 含义 |
---|---|
MIME-Version | 标识了MIME版本,并告诉接受邮件的用户代理,它正在处理一条MIME消息,以及该消息使用的是哪一个版本的MIME,任何不包含”MIME-Version”的邮件头的消息都被假定是英语明文消息。 |
Content-Description | 描述邮件的可读字符串,该邮件头是一个ASCII字符串,指出了邮件包含什么内容。 |
Conten-Id | 唯一标识符 |
Conten-Transfer-Encoding | 指出传输时如何打包 |
Conten-Type | 邮件内容的类型和格式 |
最初,RFC1521定义了7中MIME类型。每种类型都有一个或多个子类型,类型和子类型由一个斜线隔开,比如”Content-Type:video/mpeg”
类型 | 子类型实例 | 描述 |
---|---|---|
text | plain,html, xml, css | 不同版本根式的文本内容 |
image | gif, jpeg, tiff | 照片 |
audio | basic, mpeg, mp4 | 声音 |
video | mpeg, mp4, quicktime | 影片 |
model | vrml | 3D模型 |
application | pdf, javascript, zip | 由应用程序生成的数据 |
message | http, rfc | 封装的邮件 |
multipart | mixed, alternative, parallel, digest | 多类型的组合 |
发送电子邮件的计算机首先与目标计算机的25号端口建立一个TCP连接,然后在此连接上传送电子邮件。在这个端口上监听的是邮件服务器,它遵守简单邮件传输协议(SMTP),这个服务器接收入境连接请求、执行某些安全检查,并接收传递过来的邮件。如果一个邮件无法被传递,则向邮件发送方返回一个错误报告。
最终交付邮件使用的主要协议之一是Internet邮件访问协议(IMAP, Internet Message Access Protocol)。为了使用IMAP,邮件服务器必须运行IMAP服务器,它负责监听端口143,用户代理必须运行IMAP客户端。
URL提供一种定位网络资源的手段,但这些资源可以通过各种不同的方案(比如http、ftp、smtp等)来访问。
大多数URL方案的语法都建立在9部分构成的通用格式:
://:@:/;?#
最主要的包括三个部分:协议(或者成为方案scheme)、页面所在机器的DNS、唯一指向特定页面的路径。
eg. http://www.cs.washington.edu/index.html
该URL由三部分组成:协议(http)、主机的DNS(www.cs.washington.edu)和路径名(index.html)
URL默认使用的是7为二进制码表示的ASCII字符集。在URL中表示各种不安全的字符使用一种转义的方法。这种转义包含一个”%”,后面跟两个表示字符ASCII吗的十六进制数。
当点击该链接时,会发生如下步骤:
HTTP是一个简单的请求-响应协议,运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII码形式给出,而消息内容则具有一个类似MIME的格式。
在Web早期HTTP 1.0中,连接被建立起来以后浏览器只发送一个请求,之后一个响应消息被发回来,再然后TCP连接就被释放了。在那时,整个Web页面通常只包含HTML文本,因此这种连接方式足够使用。但是随着Web的发展,页面内含有大量的嵌入式内容链接,如图片等内容。建立一个单独的TCP连接来传输每个图标的操作方式代价太高。
正是这种现象导致HTTP 1.1的诞生。它支持持续连接。
HTTP每个请求都会得到一个响应,每个响应消息由一个状态行及可能的附加信息组成。状态行包括一个3位数字的状态码,该状态码指明了这个请求是否被满足,如果没有满足,那么原因是什么。
第一个数字把响应分成5大组,如表所示
代码 | 含义 | 例子 |
---|---|---|
1XX | 信息 | 100=服务器统一处理客户请求 |
2XX | 成功 | 200=请求成功; 204=没有内容 |
3XX | 重定向 | 301=移动页面; 304=缓存的页面仍然有效 |
4XX | 客户错误 | 403=禁止页面; 404=页面没找到 |
5XX | 服务器错误 | 500=服务器内部错误; 503=稍后再试 |
头 | 类型 | 内容 |
---|---|---|
User-Agent | 请求 | 有关浏览器及其平台的信息 |
Accept | 请求 | 客户可处理的页面类型 |
Accept-Charset | 请求 | 客户可接受的字符集 |
Accept-Encoding | 请求 | 客户可处理的页面编码 |
Accept-Language | 请求 | 客户可处理的自然语言 |
If-Modified-Since | 请求 | 检查新鲜度的时间和日期 |
If-None-Match | 请求 | 先前为检查新鲜度而发送的标签 |
Host | 请求 | 服务器的DNS名字 |
Authorization | 请求 | 列出客户的信任凭据 |
Referer | 请求 | 发出请求的先前URL |
Cookie | 请求 | 给服务器发回Cookie的先前URL |
Set-Cookie | 响应 | 客户存储的Cookie |
Server | 响应 | 关于服务器的信息 |
Content-Encoding | 响应 | 内容如何编码(比如: gzip) |
Content-Language | 响应 | 页面使用的自然语言 |
Content-Length | 响应 | 页面以字节计的长度 |
Content-Type | 响应 | 页面的MIME类型 |
Content-Range | 响应 | 标识了页面内容的一部分 |
Last-Modified | 响应 | 页面最后修改的时间和日期 |
Expires | 响应 | 页面不再有效的时间和日期 |
Locatioin | 响应 | 告诉客户向谁发送请求 |
Accept-Ranges | 响应 | 指出服务器能接受的请求的字节范围 |
Date | 请求/响应 | 发送消息的日期和时间 |
Range | 请求/响应 | 标识一个页面的一部分 |
Cache-Control | 请求/响应 | 指示如何处理缓存 |
ETag | 请求/响应 | 页面内容的标签 |
Upgrade | 请求/响应 | 发送方希望切换的协议 |
本部分参考资料为《HTTP协议的历史演变和设计思路》
HTTP是基于TCP/IP协议之上的应用层协议。它不涉及数据包的传输,主要规定了客户端和服务器之间的通信格式,默认是80端口。
最早版本是1991年发布的0.9版,该版本极其简单,只有一个get命令。
GET /index.html
上面的命令表示,TCP建立连接后,客户端向服务器请求(request)网页index.html。
该协议规定,服务器只能回应HTML格式的字符串,不能回应别的格式。
<html>
<body>hello worldbody>
html>
服务器发送完毕,就关闭TCP连接。
1996年5月,HTTP 1.0版本发布,内容大大增加。
首先,任何格式的内容都可以发送,这使得互联网不仅可以传输文字,还能传输图像、视频、二进制文件等。
另外,除了GET命令,还引入了POST命令和HEAD命令。
并且,HTTP请求和回应的格式也变了。除了数据部分,每次通信必须包括头信息(HTTP Header),用来描述一些元数据。
其他新增功能还包括状态码、多字符集支持、多部分发送、权限、缓存、内容编码等。
GET / HTTP/1.0
User-Agent: Mozilla/5.0(Macintosh; Intel Mac OS X 10_10_5)
Accept: */*
第一行是请求命令,必须在尾部添加协议版本(HTTP/1.0)。后面就是多行头信息,描述客户端的情况。
服务器的响应如下
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84
<html>
<body>hello worldbody>
html>
回应的格式是”头信息+一个空行(\r\n)+数据”。其中,第一行是”协议版本+状态码(status code)+状态描述”
关于字符编码,1.0版规定,头信息必须是ASCII码,后面的数据可以是任何格式。因此,服务器回应的时候,必须告诉客户端,数据是什么格式,这就是Content-Type字段的作用。
下面是常见的Content-Type字段的值
这些数据类型总称为MIME type,每个值包括一级类型和二级类型,之间用斜杠分隔。
MIME type还可以在尾部使用分号,添加参数
Content-Type:text/html;charset=utf-8
上面的类型表明,发送的是网页,编码是UTF-8
客户端请求时,可以用Accept字段声明自己可以接受哪些数据格式
Accept: */*
由于发送的数据可以是任何格式,因此可以把数据压缩后再发送。Content-Encoding字段的压缩方法
Content-Encoding:gzip
Content-Encoding:compress
Content-Encoding:deflate
客户端在请求时,用Accept-Encoding字段说明自己可以接受哪些压缩方法
Accept-Encoding:gzip, deflate
HTTP/1.0主要缺点就是每次TCP连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须新建一个连接。
TCP连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢,所以HTTP/1.0版本的性能较差。
1997年1月,HTTP/1.1版本发布,只比1.0晚了半年。
1.1版本最大的变化就是引入持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求复用。
客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过规范的做法是,客户端在最后一个请求你是发送Connection:close,明确要求服务器关闭TCP连接。
1.1版本还引入了管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求。这样就进一步改进了HTTP效率。
eg. 客户端需要请求两个资源,以前的做法是在同一个TCP连接里面,先发送A请求,然后等待服务器做出回应,收到后再发出B请求。管道机制则是允许浏览器发出A请求和B请求,但是服务器还是按照顺序,先回应A请求,再回应B请求。
一个TCP连接限制可以传送多个回应,就必须要有一种机制,区分数据包属于哪一个回应。这就需要Content-type字段的作用,声明本次回应的数据长度
Content-Length:3495
上面的字段高速浏览器,本次回应的长度是3495个字节,后面的字节就属于下一个回应了。
在1.0版本中,Content-Length字段不是必须的,因为浏览器发现服务器关闭了TCP连接,就表明收到的数据包已经全了
1.1版本规定可以不使用Content-Length字段,而使用分块传输编码。
1.1版本还增加了:PUT, PATCH, HEAD, OPTIONS, DELETE方法。
另外客户端请求的头信息新增了HOST字段,用来指定服务器的域名。
有了Host字段,就可以将请求发往同一台服务器上不同的网站,为虚拟主机的兴起打下了基础。
虽然HTTP/1.1允许复用TCP连接,但是同一个TCP连接里,所有的数据通信时按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等待,成为队头阻塞。
为了避免这种问题,要么减少请求数,要么同时多开持久连接。这导致了很多网页优化技巧,比如合并脚本和样式表、将图片嵌入CSS代码、域名分片等待。
2015年,HTTP/2发布,它不叫HTTP/2.0是因为标准委员会不打算再发布子版本了,下一个版本将是HTTP/3。
HTTP/1.1版的头信息是文本(ASCII编码),数据体可以是文本,也可以是二进制。
HTTP/2则是彻底的二进制协议,头信息和数据体都是二进制,并且统称为帧(frame):头信息帧和数据帧。
HTTP/2复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求和回应,而不用按照顺序一一对应,这样就避免了”队头阻塞”。
HTTP/2将每个请求或回应的数据包,成为一个数据流。每个数据里都有一个独一无二的编号。数据包发送时,都必须标记数据流ID,另外还规定客户端发出的数据流,ID一律为奇数,服务器发出的,ID一律为偶数。客户端还可以指定数据流的优先级,优先级越高,服务器就会越早回应。
另外数据流发送到一半的时候,客户端和服务器可以发送信号(RST_STREAM帧),取消这个数据流。1.1版本取消数据流的唯一方法就是关闭TCP连接。这就是说HTTP/2可以取消某一次请求,同时保证TCP连接还打开这。
HTTP协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如cookie和user agent,一模一样的内容,每次请求必须附带,浪费很多宽带,也影响速度。
HTTP/2对这一点做了优化,引入了头信息压缩机制。一方面头信息使用gzip或compress压缩后再发送;另一方面客户端和服务器同时维护一张头信息表,所有字段都会存入这个表生成一个索引号,以后就不发送同样字段,只发送索引号,这样就提高了速度。
HTTP/2允许服务器未经请求,主动向客户端发送资源,叫做服务器推送。
常见的场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实服务器可以预期到客户端请求网页后,很坑内再请求静态资源,所以就主动把这些静态资源随着网页一起发送给客户端。
明文&密文: 待加密的消息称为明文(plaintext),它经过一个以密钥(key)为参数的函数变换,这个过程的结果就是所谓的密文(ciphertext).
密码破解的技术就是所谓的密码分析学(cryptanalysis),而它和涉及密码的密码编码学(cryptography)合起来统称为密码学(cryptology)。
我们的基本模型是一个稳定的、广泛公开的通用方法,它用一个秘密的、易改变的密钥作为参数。
让密码分析者知道加解密算法,并且把所有的秘密信息全部放在秘钥中,这种思想称为Kerckhoff原理。Kerckhoff的原则是:所有算法必须是公开的而秘钥是保密的。
由于真正的秘密在密钥中,所以它的长度是一个非常重要的设计元素。密钥越长,则密码分析者要消耗的工作因子就越高,通过穷举搜索整个密钥空间来破解密码系统的工作因子随着密钥长度增加而呈指数递增。保密性来自于强而牢固的(但是公开的)算法和密钥的长度。为了防止你的孩子阅读你的邮件,64位密钥足够了。但是对于常规的商业用途,至少应该使用128位密钥。对于大规模的政府机构,则至少需要256位的秘钥。
1977年1月,美国政府采用了IBM开发的一个乘积密码作为非机密信息的官方标准,这个密码算法即数据加密标准(DES, Data Encryption Standard)。
对称秘钥的前提是双方必须就共享秘钥达成一致,但是这样做的前提就是需要通信,通过人为的协商确定秘钥,之后才能进行加密通信。
假设Alice和Bob通信,他们没有共享一个秘钥,但是Bob有两个秘钥,一个是公有的,所有人都知道的公钥(public key),另一个是只有Bob知道的私钥(private key)。用 K_B+ 和 K_B− 分别表示Bob的公钥和私钥。Alice与Bob通信时,,先取得Bob的公钥 K_B+ ,然后用这个公钥加密报文m,得到 K_B+(m) ,Bob接收到Alice的加密报文后,用私钥对其进行解密 K_B−(K_B+(m))=m
在这个过程中,最常见的加密解密算法是RSA
关于计算机网络的书籍推荐
讲述计算机网络最经典的当属Andrew S. Tanenbaum的《计算机网络》第五版。
另外推荐两本:
如果只是了解网络基础知识,看上面3本即可,如果做开发,则需要:
《TCP/IP详解》三卷本
《用TCP/IP进行网际互联》三卷本
《TCP/IP指南》+《IPv6》四卷本
其中,《TCP/IP详解》的作者还写了另外2本经典著作:《Unix环境高级编程》,《Unix网络编程》。作者W.Richard Stevens