HTTP概述
HTTP协议用于约定服务端(如Web服务器Tomcat、IIS)和客户端(如浏览器、APP)通信的消息格式和响应方式。了解HTTP协议内容有助于优化Http请求,如断点下载、多线程下载、防盗链等功能的实现。HTTP协议是建立在TCP协议之上的,理论上只要有一个Socket就能够实现Http消息的请求,实现比如HttpClient、UrlConnection的请求操作。只要有一个SocketServer就能够实现Http消息的响应,实现比如Tomcat、IIS等Web服务器的功能,比如在手机上部署网站,用户可以在浏览器端访问同一网络下的手机部署的站点。
HTTP请求协议详解
HTTP1.1的请求协议报文结构如下图,大体上可以分为三块,即请求行、头部、消息主体。
请求行
请求行包含HTTP请求方法、请求的URL、HTTP协议版本三个内容,它们之间以空格间隔,并以回车+换行结束。
HTTP请求方法有下面几种,常用的有GET、POST请求。
- OPTIONS
- GET
- HEAD
- POST
- DELETE
- TRACE
- CONNECT
请求头部
头部可以分成三个部分,为常用头域、请求头域、实体头域。其中常用头域和实体头域部分内容在响应协议部分也有相同的定义。
常用头域
常用头域名称 | 作用描述 |
---|---|
Cache-Control | 缓存控制 |
Connection | HTTP 1.1默认是支持长连接的(Keep-Alive),如果不希望支持长连接则需要在此域中写入close |
Date | 表明消息产生的日期和时间 |
Pragma | |
Trailer | |
Transfer-Encoding | 告知接收端为了保证报文的可靠传输,对报文采用了什么编码方式 |
Upgrade | 给出了发送端可能想要”升级”使用的新版本或协议 |
Via | 显示了报文经过的中间节点(代理、网关) |
Warning |
请求头域
请求头域名称 | 作用描述 |
---|---|
Accept | 指明请求端可以接受处理的媒体类型 |
Accept-Charset | 指明请求端可以接受的字符集 |
Accept-Encoding | 指明请求端可以接受的编码格式 |
Authorization | 授权 |
Expect | 允许客户端列出某请求所要求的服务器行为 |
From | 提供了客户端用户的E-mail地址 |
Host | 指明请求端的网络主机和端口号 |
If-Match | 服务端在响应头部里面返回ETag信息,客户端请求时在头部添加If-Match(值为响应的ETag),服务端接收后判断ETag是否相同,若相同则处理请求,否则不处理请求。 |
If-Modified-Since | 客户端在请求某一资源文件时,在头部加上If-Modified-Since(值为该资源文件的最后修改时间),服务端接收后将客户端上报的修改时间与服务器存储的文件的最后修改时间做对比,如果相同,说明资源文件没有更新,返回304状态码,告诉客户端使用原来的缓存文件。否则返回资源内容。 |
If-None-Match | 服务端在响应头部里面返回ETag信息,客户端请求时在头部添加If-None-Match(值为响应的ETag),服务端接收后判断ETag是否相同,若相同,说明资源没有更新,返回304状态码,告诉客户端使用原来的缓存文件。否则返回资源内容。 |
If-Range | 该头域与Range头域一起使用,服务端在响应头部里面返回ETag信息,客户端请求时在头部添加If-Range(值为响应的ETag),服务端接收后判断ETag是否相同,若相同,则返回状态码206,返回内容为Range指定的字节范围。若不相同,则返回状态码200,返回内容为整个实体。 |
If-Unmodified-Since | 客户端在请求某一资源文件时,在头部加上If-Modified-Since(值为该资源文件的最后修改时间),端接收后将客户端上报的修改时间与服务器存储的文件的最后修改时间做对比,如果相同,则返回资源内容,如果不相同则返回状态码412。 |
Max-Forwards | 配合TRACE、OPTIONS方法使用,限制在通往服务器的路径上的代理或网关的数量。 |
Proxy-Authorization | 代理授权 |
Range | 表示客户端向服务端请求指定范围的字节数量:Range:bytes=0-500表示请求第1个到第501个的字节数量。Range:bytes=100-表示请求第101到文件倒数第一个字节的字节数量。Range:bytes=-500表示请求最后500个字节的数量。Range可以同时指定多组(Range:bytes=500-600,601-999)。并不是所有的服务端都支持字节范围请求的,如果支持字节范围请求,服务端会返回状态码206,若不支持则会返回200,客户端需要根据状态码来判断服务端是否支持字节范围操作。此域可用于断点下载,即在断点处请求后面的内容,也可用于多线程下载同一个文件,每个线程负责一个文件的一部分下载工作,多个线程协同完成整个文件的下载。 |
Referer | 用于指定客户端请求的来源,是从搜索引擎过来的?还是从其它网站链接过来的?服务器根据此域,有时可以用做防盗链处理,不在指定范围内的来源,统统拒绝。 |
TE | 指明客户端可以接受哪些传输编码。 |
实体头域
实体头域名称 | 作用描述 |
---|---|
Allow | 指明被请求的资源所支持的方法,如GET、HEAD、PUT |
Content-Encoding | 指明实体内容所采用的编码方式 |
Content-Language | 指明实体内容使用的语言 |
Content-Length | 指明请求实体的字节数量 |
Content-Location | 可以用来为实体提供对应资源的位置 |
Content-MD5 | 指定实体内容的MD5,用于内容的完整性校验(base64的128位MD5) |
Content-Range | |
Content-Type | 指定实体的媒体类型 |
Expires | 指明实体的过期时间 |
Last-Modified | 指明实体最后被修改的时间 |
HTTP响应协议详解
HTTP1.1的响应协议报文结构如下图,大体上可以分为三块,即状态行、头部、消息主体。
状态行
状态行包含HTTP协议版本、状态码、原因短语三个内容,它们之间以空格间隔,并以回车+换行结束。
状态码由三位数字组成,第一位数字定义了响应类型,主要有如下五种类型的状态码
状态码类型 | 作用描述 |
---|---|
1xx | 报告(请求被接收,继续处理) |
2xx | 成功(请求被成功的接收并处理) |
3xx | 重发 |
4xx | 客户端出错(客户端错误的协议格式和不能处理的请求) |
5xx | 服务器出错(服务器无法完成有效的请求处理) |
状态码和对应的原因短语详细描述
状态码 | 原因短语 | 中文描述 |
---|---|---|
100 | Continue | 继续 |
101 | Switching Protocols | 切换协议 |
200 | OK | 成功 |
201 | Created | 已创建 |
202 | Accepted | 接受 |
203 | Non-Authoritative information | 非权威信息 |
204 | No Content | 无内容 |
205 | Reset Content | 重置内容 |
206 | Partial Content | 部分内容 |
300 | Multiple Choices | 多个选择 |
301 | Moved Permanently | 永久移动 |
302 | Found | 发现 |
303 | See Other | 见其它 |
304 | Not Modified | 没有改变 |
305 | Use Proxy | 使用代理 |
307 | Temporary Redirect | 临时重发 |
400 | Bad Request | 坏请求 |
401 | Unauthorized | 未授权的 |
402 | Payment Required | 必需的支付 |
403 | Forbidden | 禁用 |
404 | Not Found | 没有找到 |
405 | Method Not Allowed | 方法不被允许 |
406 | Not Acceptable | 不可接受的 |
407 | Proxy Authentication Required | 需要代理验证 |
408 | Request Timeout | 请求超时 |
409 | Confilict | 冲突 |
410 | Gone | 不存在 |
411 | Length Required | 长度必需 |
412 | Precondition Failed | 先决条件失败 |
413 | Request Entity Too Large | 请求实体太大 |
414 | Request-URI Too Long | 请求URI太长 |
415 | Unsupported Media Type | 不支持的媒体类型 |
416 | Requested Range Not Satisfiable | 请求范围不被满足 |
417 | Expectation Failed | 期望失败 |
500 | Internal Server Error | 内部服务器错误 |
501 | Not Implemented | 服务端没有实现 |
502 | Bad Gateway | 坏网关 |
503 | Service Unavailable | 服务不能获得 |
504 | Gateway Timeout | 网关超时 |
505 | HTTP Version Not Supported | HTTP协议版本不支持 |
响应头域
响应头域名称 | 作用描述 |
---|---|
Accept-Ranges | 服务器向客户端指明服务器对范围请求的接受度 |
Age | 从原始服务器到代理缓存形成的估算时间(以秒计,非负) |
ETag | 实体标签 |
Location | 指定重定向的URI |
Proxy-Autenticate | 它指出认证方案和可应用到代理的该URL上的参数 |
Retry-After | 如果实体暂时不可取,通知客户端在指定时间之后再次尝试 |
Server | 指明服务器用于处理请求的软件信息 |
Vary | 告诉下游代理是使用缓存响应还是从原始服务器请求 |
WWW-Authenticate | 表明客户端请求实体应该使用的授权方案 |
参考资料
HTTP 2.0 协议详解
一、HTTP 2.0:改进传输性能
HTTP 2.0 的主要目标是改进传输性能,实现低延迟和高吞吐量。从另一方面看,HTTP 的高层协议语义并不会因为这次版本升级而受影响。所有HTTP 首部、值,以及它们的使用场景都不会变。
现有的任何网站和应用,无需做任何修改都可以在HTTP 2.0 上跑起来。不用为了利用HTTP 2.0 的好处而修改标记。HTTP 服务器必须运行HTTP 2.0 协议,但大部分用户都不会因此而受到影响。
二、HTTP2.0历史及其与SPDY的渊源
SPDY 是谷歌开发的一个实验性协议,于2009 年年中发布,主要目标是通过解决HTTP 1.1 中广为人知的一些性能限制,来减少网页的加载延迟
SPDY协议设定的目标
页面加载时间(PLT,Page • Load Time)降低 50%;
无需网站作者修改任何内容;
把部署复杂性降至最低,无需变更网络基础设施;
与开源社区合作开发这个新协议;
-
收集真实性能数据,验证这个实验性协议是否有效。
注:为了达到降低50% 页面加载时间的目标,SPDY 引入了一个新的二进制分帧数据层,以实现多向请求和响应、优先次序、最小化及消除不必要的网络延迟,目的是更有效地利用底层TCP 连接;
HTTP-WG(HTTP Working Group)在2012 年初把HTTP 2.0提到了议事日程,吸取SPDY 的经验教训,并在此基础上制定官方标准
三、HTTP2.0深入探究
HTTP/2.0 应该满足如下条件:
- 相对于使用TCP 的HTTP 1.1,• 用户在大多数情况下的感知延迟要有实质上、可度量的改进;
- 解决 HTTP 中的“队首阻塞”问题;
- 并行操作无需与服务器建立多个连接,从而改进 TCP 的利用率,特别是拥塞控制方面;
- 保持 HTTP 1.1 的语义,利用现有文档,包括(但不限于)HTTP 方法、状态码、URI,以及首部字段;
- 明确规定 HTTP 2.0 如何与 HTTP 1.x 互操作,特别是在中间介质上;
- 明确指出所有新的可扩展机制以及适当的扩展策略。
HTTP 2.0 致力于突破上一代标准众所周知的性能限制,但它也是对之前1.x 标准的扩展,而非替代。之所以要递增一个大版本到2.0,主要是因为它改变了客户端与服务器之间交换数据的方式,HTTP 2.0 增加了新的二进制分帧数据层
四、HTTP2.0设计和技术目标
HTTP/2.0 通过支持首部字段压缩和在同一连接上发送多个并发消息,让应用更有效地利用网络资源,减少感知的延迟时间。而且,它还支持服务器到客户端的主动推送机制。
-
二进制分帧层
- HTTP 2.0 二进制分帧层,封装HTTP 消息并在客户端与服务器之间传输
HTTP2.0 将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码。
注:HTTPS 是二进制分帧的另一个典型示例:所有HTTP 消息都以透明的方式为我们编码和解码,不必对应用进行任何修改。HTTP2.0工作原理有点类似
-
流、消息和帧
- 流:流是连接中的一个虚拟信道,可以承载双向的消息;每个流都有一个唯一的整数标识符(1、2…N);
- 消息:是指逻辑上的 HTTP 消息,比如请求、响应等,由一或多个帧组成。
- 帧:HTTP 2.0 通信的最小单位,每个帧包含帧首部,至少也会标识出当前帧所属的流,承载着特定类型的数据,如 HTTP 首部、负荷,等等
- HTTP 2.0 的所有帧都采用二进制编码,所有首部数据都会被压缩。
- 所有通信都在一个 TCP 连接上完成。
- HTTP 2.0 把HTTP协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息。相应地,很多流可以并行地在同一个TCP 连接上交换消息
-
多向请求与响应
-
HTTP 2.0 中新的二进制分帧层突破了这些限制,实现了多向请求和响应:客户端和服务器可以把HTTP 消息分解为互不依赖的帧,然后乱序发送,最后再在另一端把它们重新组合起来
图中包含了同一个连接上多个传输中的数据流:客户端正在向服务器传输一个DATA 帧(stream 5),与此同时,服务器正向客户端乱序发送stream 1 和stream 3的一系列帧。此时,一个连接上有3 个请求/ 响应并行交换!
把HTTP 消息分解为独立的帧,交错发送,然后在另一端重新组装是HTTP 2.0 最重要的一项增强。这个机制会在整个Web 技术栈中引发一系列连锁反应,从而带来巨大的性能提升。
* 可以并行交错地发送请求,请求之间互不影响; * 可以并行交错地发送响应,响应之间互不干扰; * 只使用一个连接即可并行发送多个请求和响应; * 消除不必要的延迟,从而减少页面加载的时间; * 不必再为绕过 HTTP 1.x 限制而多做很多工作;
- HTTP 2.0 的二进制分帧机制解决了HTTP 1.x 中存在的队首阻塞问题,也消除了并行处理和发送请求及响应时对多个连接的依赖。
-
-
请求优先级
- 把HTTP 消息分解为很多独立的帧之后,就可以通过优化这些帧的交错和传输顺序,每个流都可以带有一个31 比特的优先值:0 表示最高优先级;2的31次方-1 表示最低优先级。
- 服务器可以根据流的优先级,控制资源分配(CPU、内存、带宽),而在响应数据准备好之后,优先将最高优先级的帧发送给客户端。
- HTTP 2.0 一举解决了所有这些低效的问题:浏览器可以在发现资源时立即分派请求,指定每个流的优先级,让服务器决定最优的响应次序。这样请求就不必排队了,既节省了时间,也最大限度地利用了每个连接。
-
每个来源一个连接
-
有了新的分帧机制后,HTTP 2.0 不再依赖多个TCP 连接去实现多流并行了。每个数据流都拆分成很多帧,而这些帧可以交错,还可以分别优先级。HTTP 2.0 连接都是持久化的,而且客户端与服务器之间也只需要一个连接即可。
- 实验表明,客户端使用更少的连接肯定可以降低延迟时间。HTTP 2.0 发送的总分组数量比HTTP 差不多要少40%。
- 大多数HTTP 连接的时间都很短,而且是突发性的,但TCP 只在长时间连接传输大块数据时效率才最高。HTTP 2.0 通过让所有数据流共用同一个连接,可以更有效地使用TCP 连接。
-
-
流量控制
-
HTTP 2.0 为数据流和连接的流量控制提供了一个简单的机制:
- 流量控制基于每一跳进行,而非端到端的控制;
- 流量控制基于窗口更新帧进行,即接收方广播自己准备接收某个数据流的多少字节,以及对整个连接要接收多少字节;
- 流量控制窗口大小通过 WINDOW_UPDATE 帧更新,这个字段指定了流 ID 和窗口大小递增值;
- 流量控制有方向性,即接收方可能根据自己的情况为每个流乃至整个连接设置任意窗口大小;
- 流量控制可以由接收方禁用,包括针对个别的流和针对整个连接。
-
-
服务器推送
-
HTTP 2.0 新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。服务器向客户端推送资源无需客户端明确地请求。
HTTP 2.0 连接后,客户端与服务器交换SETTINGS 帧,借此可以限定双向并发的流的最大数量。因此,客户端可以限定推送流的数量,或者通过把这个值设置为0 而完全禁用服务器推送。
所有推送的资源都遵守同源策略。换句话说,服务器不能随便将第三方资源推送给客户端,而必须是经过双方确认才行。
PUSH_PROMISE:所有服务器推送流都由PUSH_PROMISE 发端,服务器向客户端发出的有意推送所述资源的信号。客户端接收到PUSH_PROMISE 帧之后,可以视自身需求选择拒绝这个流
-
几点限制:
- 服务器必须遵循请求- 响应的循环,只能借着对请求的响应推送资源
- PUSH_PROMISE 帧必须在返回响应之前发送,以免客户端出现竞态条件。
-
-
首部压缩(HPACK压缩算法,一边用index mapping table压缩,一边编码,这个table由静态表和动态表组成)
http2.0会压缩首部元数据:在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键值对,对于相同的数据,不再通过每次请求和响应发送;“首部表”在http2.0的连接存续期内始终存在,由客户端和服务器共同渐进地更新;每个新的首部键值对要么追加到当前表的末尾,要么替换表中之前的值。
-
http2.0首部差异化传输
- 请求与响应首部的定义在HTTP2.0中基本没有改变,只是所有首部键必须全部小写,而且请求行要独立为 :method、:scheme、:host、:path这些键值对。
-
有效的HTTP2.0升级与发现
-
大多数现代浏览器都内置有高效的后台升级机制,支持HTTP2.0的客户端在发起新请求之前,必须能发现服务器及所有中间设备是否支持HTTP2.0协议。有三种可能的情况:
- 通过TLS和ALPN发起新的HTTPS连接;
- 根据之前的信息发起新的HTTP连接;
- 没有之前的信息而发起新的HTTP连接。
HTTPS 协商过程中有一个环节会使用ALPN(应用层协议协商)。减少网络延迟是HTTP 2.0 的关键条件,因此在建立HTTPS 连接时一定会用到ALPN协商。
通过常规非加密信道建立HTTP2.0连接需要多做一点工作。因为HTTP1.0和HTTP2.0都使用同一个端口(80),有没有服务器是否支持HTTP2.0的其他任何信息,此时客户端只能使用HTTP Upgrade机制通过协调确定适当的协议:
Upgrade: HTTP/2.0 ➊ HTTP2-Settings: (SETTINGS payload) ➋ HTTP/1.1 200 OK ➌ HTTP/1.1 101 Switching Protocols ➍ ...
➊ 发起带有HTTP 2.0 Upgrade 首部的HTTP 1.1 请求 ➋ HTTP/2.0 SETTINGS 净荷的Base64 URL 编码 ➌ 服务器拒绝升级,通过HTTP 1.1 返回响应 ➍ 服务器接受HTTP 2.0 升级,切换到新分帧
-
HTTP2.0二进制分帧简介
建立HTTP2.0连接后,客户端与服务器会通过交换帧来通信,帧是基于这个新协议通信的最小单位。所有帧都共享一个8字节的首部,其中包含帧的长度、类型、标志,还有一个保留位和一个31位的流标识符。
-
发起新流
- 在发送应用数据之前,必须创建一个新流并随之发送相应的元数据,比如流优先级、HTTP 首部等;
- 客户端通过发送HEADERS帧来发起新流;
- 服务器通过发送 PUSH_PROMISE 帧来发起推送流。
-
发送应用数据
- 创建新流并发送HTTP 首部之后,接下来就是利用DATA 帧。应用数据可以分为多个DATA 帧,最后一帧要翻转帧首部的END_STREAM 字段
- HTTP 2.0 标准要求DATA 帧不能超过2的14次方-1(16383)字节。长度超过这个阀值的数据,就得分帧发送。
-
HTTP2.0帧数据流分析
- HTTP2.0在共享的连接上同时发送请求和响应
- 3 个流的 ID 都是奇数,说明都是客户端发起的
- 服务器发送的 stream 1 包含多个 DATA 帧,这是对客户端之前请求的响应数据
- 服务器在交错发送 stream 1 的 DATA 帧和 stream 3 的 HEADERS 帧,这就是响应的多路复用!
- 客户端正在发送 stream 5 的 DATA 帧,表明 HEADERS 帧之前已经发送过了。
针对HTTP2.0的优化建议
-
去掉对1.x的优化
- 每个来源使用一个连接,HTTP 2.0 通过将一个TCP 连接的吞吐量最大化来提升性能。
- 去掉不必要的文件合并和图片拼接:HTTP 2.0,很多小资源都可以并行发送
- 利用服务器推送:之前针对HTTP 1.x 而嵌入的大多数资源,都可以而且应该通过服务器推送来交付。
-
双协议应用策略
- 相同的应用代码,双协议部署
- 分离应用代码,双协议部署
- 动态HTTP 1.x和HTTP 2.0优化:某些自动化的Web 优化框架在响应请求时动态重写交付的应用代码(包括连接、拼合、分区,等等)
- 单协议部署
-
1.x与2.0的相互转换
-
评估服务器质量与性能
- HTTP 2.0 服务器必须理解流优先级;
- HTTP 2.0 服务器必须根据优先级处理响应和交付资源;
- HTTP 2.0 服务器必须支持服务器推送;
- HTTP 2.0 服务器应该提供不同推送策略的实现。
-
2.0与TLS
-
两种可能出现ALPN 协商和TLS 终止的情况
- TLS 连接可能会在 HTTP 2.0 服务器上终止;
- TLS 连接可能会在上游(如负载均衡器)上终止。
第一种情况要求HTTP 2.0 服务器能够处理TLS;
第二种情况建立一条加密信道,直接将非加密的HTTP 2.0 流发送到服务器
-
-
负载均衡器、代理及应用服务器
- 要在TLS 之上实现HTTP 2.0通信,终端服务器必须支持 ALPN;
- 尽可能在接近用户的地方终止 TLS;
- 如果无法支持 ALPN,那么选择 TCP 负载均衡模式;
- 如果无法支持 ALPN 且 TCP 负载均衡也做不到,那么就退而求其次,在非加密信道上使用HTTP 的Upgrade 流;
TCP/IP
TCP/IP是个协议组,可分为三个层次:网络层、传输层和应用层。
在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。
在传输层中有TCP协议与UDP协议。
在应用层有:TCP包括FTP、HTTP、TELNET、SMTP等协议
UDP包括DNS、TFTP等协议
短连接
连接->传输数据->关闭连接
HTTP是无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。
也可以这样说:短连接是指SOCKET连接后发送后接收完数据后马上断开连接。
长连接
连接->传输数据->保持连接 -> 传输数据-> 。。。 ->关闭连接。
长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差。
http的长连接
HTTP也可以建立长连接的,使用Connection:keep-alive,HTTP 1.1默认进行持久连接。HTTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持(貌似最新的 http1.0 可以显示的指定 keep-alive),但还是无状态的,或者说是不可以信任的。
什么时候用长连接,短连接?
长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。
而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。
总之,长连接和短连接的选择要视情况而定。
发送接收方式
1、异步
报文发送和接收是分开的,相互独立的,互不影响。这种方式又分两种情况:
(1)异步双工:接收和发送在同一个程序中,由两个不同的子进程分别负责发送和接收
(2)异步单工:接收和发送是用两个不同的程序来完成。
2、同步
报文发送和接收是同步进行,既报文发送后等待接收返回报文。 同步方式一般需要考虑超时问题,即报文发出去后不能无限等待,需要设定超时时间,超过该时间发送方不再等待读返回报文,直接通知超时返回。
在长连接中一般是没有条件能够判断读写什么时候结束,所以必须要加长度报文头。读函数先是读取报文头的长度,再根据这个长度去读相应长度的报文。
Socket是什么
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
[图片上传失败...(image-bfb4aa-1527588784406)]
通信过程:
[图片上传失败...(image-90d03b-1527588784405)]
主机 A 的应用程序要能和主机 B 的应用程序通信,必须通过 Socket 建立连接,而建立 Socket 连接必须需要底层 TCP/IP 协议来建立 TCP 连接。建立 TCP 连接需要底层 IP 协议来寻址网络中的主机。我们知道网络层使用的 IP 协议可以帮助我们根据 IP 地址来找到目标主机,但是一台主机上可能运行着多个应用程序,如何才能与指定的应用程序通信就要通过 TCP 或 UPD 的地址也就是端口号来指定。这样就可以通过一个 Socket 实例唯一代表一个主机上的一个应用程序的通信链路了。
建立通信链路
当客户端要与服务端通信,客户端首先要创建一个 Socket 实例,操作系统将为这个 Socket 实例分配一个没有被使用的本地端口号,并创建一个包含本地和远程地址和端口号的套接字数据结构,这个数据结构将一直保存在系统中直到这个连接关闭。在创建 Socket 实例的构造函数正确返回之前,将要进行 TCP 的三次握手协议,TCP 握手协议完成后,Socket 实例对象将创建完成,否则将抛出 IOException 错误。
与之对应的服务端将创建一个 ServerSocket 实例,ServerSocket 创建比较简单只要指定的端口号没有被占用,一般实例创建都会成功,同时操作系统也会为 ServerSocket 实例创建一个底层数据结构,这个数据结构中包含指定监听的端口号和包含监听地址的通配符,通常情况下都是“*”即监听所有地址。之后当调用 accept() 方法时,将进入阻塞状态,等待客户端的请求。当一个新的请求到来时,将为这个连接创建一个新的套接字数据结构,该套接字数据的信息包含的地址和端口信息正是请求源地址和端口。这个新创建的数据结构将会关联到 ServerSocket 实例的一个未完成的连接数据结构列表中,注意这时服务端与之对应的 Socket 实例并没有完成创建,而要等到与客户端的三次握手完成后,这个服务端的 Socket 实例才会返回,并将这个 Socket 实例对应的数据结构从未完成列表中移到已完成列表中。所以 ServerSocket 所关联的列表中每个数据结构,都代表与一个客户端的建立的 TCP 连接。
备注:
Windows 下单机最大TCP连接数
调整系统参数来调整单机的最大TCP连接数,Windows 下单机的TCP连接数有多个参数共同决定:
以下都是通过修改注册表[HKEY_LOCAL_MACHINE \System \CurrentControlSet \Services \Tcpip \Parameters]
**1.最大TCP连接数 ** TcpNumConnections
2.TCP关闭延迟时间 TCPTimedWaitDelay (30-240)s
3.最大动态端口数 MaxUserPort (Default = 5000, Max = 65534) TCP客户端和服务器连接时,客户端必须分配一个动态端口,默认情况下这个动态端口的分配范围为 1024-5000 ,也就是说默认情况下,客户端最多可以同时发起3977 Socket 连接
4.最大TCB 数量 MaxFreeTcbs
系统为每个TCP 连接分配一个TCP 控制块(TCP control block or TCB),这个控制块用于缓存TCP连接的一些参数,每个TCB需要分配 0.5 KB的pagepool 和 0.5KB 的Non-pagepool,也就说,每个TCP连接会占用 1KB 的系统内存。
非Server版本,MaxFreeTcbs 的默认值为1000 (64M 以上物理内存)Server 版本,这个的默认值为 2000。也就是说,默认情况下,Server 版本最多同时可以建立并保持2000个TCP 连接。
5. 最大TCB Hash table 数量 MaxHashTableSize TCB 是通过Hash table 来管理的。
这个值指明分配 pagepool 内存的数量,也就是说,如果MaxFreeTcbs = 1000 , 则 pagepool 的内存数量为 500KB那么 MaxHashTableSize 应大于 500 才行。这个数量越大,则Hash table 的冗余度就越高,每次分配和查找 TCP 连接用时就越少。这个值必须是2的幂,且最大为65536.
IBM WebSphere Voice Server 在windows server 2003 下的典型配置
MaxUserPort = 65534 (Decimal)
MaxHashTableSize = 65536 (Decimal)
MaxFreeTcbs = 16000 (Decimal)
这里我们可以看到 MaxHashTableSize 被配置为比MaxFreeTcbs 大4倍,这样可以大大增加TCP建立的速度
短连接和长连接
短连接:每次Http请求都会建立Tcp连接,管理容易
-
长连接:只需要建立一次Tcp连接,以后Http请求重复使用同一个Tcp连接,管理难
HTTP1.1规定了默认保持长连接(HTTP persistent connection ,也有翻译为持久连接),数据传输完成了保持TCP连接不断开(不发RST包、不四次握手),等待在同域名下继续用这个通道传输数据;相反的就是短连接
如果服务器没有告诉客户端超时时间也没关系,服务端可能主动发起四次握手断开TCP连接,客户端能够知道该TCP连接已经无效;另外TCP还有心跳包来检测当前连接是否还活着,方法很多,避免浪费资源。
在长连接的应用场景下,client端一般不会主动关闭它们之间的连接,Client与server之间的连接如果一直不关闭的话,会存在一个问题,随着客户端连接越来越多,server早晚有扛不住的时候,这时候server端需要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可以避免一些恶意连接导致server端服务受损;如果条件再允许就可以以客户端机器为颗粒度,限制每个客户端的最大长连接数,这样可以完全避免某个蛋疼的客户端连累后端服务。
长连接和短连接的产生在于client和server采取的关闭策略,具体的应用场景采用具体的策略,没有十全十美的选择,只有合适的选择
应用场景区别:
- 一般长连接(追求实时性高的场景)用于少数client-end to server-end的频繁的通信,例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。
- 而像WEB网站的http服务一般都用短链接(追求资源易回收场景),因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源。
短轮询和长轮询
和短连接和长连接有本质区别
1. 短轮询:重复发送Http请求,查询目标事件是否完成,优点:编写简单,缺点:浪费带宽和服务器资源
2. 长轮询:在服务端hold住Http请求(死循环或者sleep等等方式),等到目标时间发生,返回Http响应。优点:在无消息的情况下不会频繁的请求,缺点:编写复杂