网络体系的分层结构
分层 | 说明 |
---|---|
应用层(HTTP、FTP、DNS、SMTP 等) | 定义了如何包装和解析数据,应用层是 http 协议的话,则会按照协议规定包装数据,如按照请求行、请求头、请求体包装,包装好数据后将数据传至运输层 |
运输层(TCP、UDP 等) | 运输层有 TCP 和 UDP 两种,分别对应可靠和不可靠的运输。在这一层,一般都是和 Socket 打交道,Socket 是一组封装的编程调用接口,通过它,我们就能操作 TCP、UDP 进行连接的建立等。这一层指定了把数据送到对应的端口号 |
网络层(IP 等) | 这一层IP协议,以及一些路由选择协议等等,所以这一层的指定了数据要传输到哪个IP地址。中间涉及到一些最优线路,路由选择算法等 |
数据链路层(ARP) | 负责把 IP 地址解析为 MAC 地址,即硬件地址,这样就找到了对应的唯一的机器 |
物理层 | 提供二进制流传输服务,也就是真正开始通过传输介质(有线、无线)开始进行数据的传输 |
HTTP 相关
通用头部
请求报文
http 请求由三部分组成,分别是:请求行、请求头、请求体
请求行
请求行以一个方法符号开头,以空格分开,格式如下:
Method Request-URI HTTP-Version CRLF
名称 | 说明 |
---|---|
Method | 请求方法如 post/get |
Request-URI | 资源标识符(请求路径) |
HTTP-Version | 请求的HTTP协议版本 |
CRLF | 回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符) |
请求方法
- HTTP 1.0
名称 | 说明 |
---|---|
GET | 请求获取 Request-URI 所标识的资源 |
POST | 在 Request-URI 所标识的资源后附加新的数据 |
HEAD | 请求获取由 Request-URI 所标识的资源的响应消息报头 |
- HTTP 1.1 新增
名称 | 说明 |
---|---|
PUT | 请求服务器存储一个资源,并用 Request-URI 作为其标识 |
DELETE | 请求服务器删除 Request-URI 所标识的资源 |
TRACE | 请求服务器回送收到的请求信息,主要用于测试或诊断 |
CONNECT | 保留将来使用 |
OPTIONS | 请求查询服务器的性能,或者查询与资源相关的选项和需求 |
- GET & POST 的区别
区别 | 说明 |
---|---|
数据传输方式 | GET 请求通过 URL 传输数据,而 POST 的数据通过请求体传输。 |
安全性 | POST的数据因为在请求主体内,所以有一定的安全性保证,而 GET 的数据在 URL 中,通过历史记录,缓存很容易查到数据信息。 |
数据类型不同 | GET只允许 ASCII 字符,而 POST 无限制 |
特性 | GET 是安全无害(只读)且幂等(多次提交等于一次提交),而 POST 是非安全非幂等,可能重复提交表单 |
请求头
Header | 解释 | 示例 |
---|---|---|
Accept | 指定客户端能够接收的内容类型 | Accept: text/plain, text/html,application/json |
Accept-Charset | 浏览器可以接受的字符编码集 | Accept-Charset: iso-8859-5 |
Accept-Encoding | 指定浏览器可以支持的web服务器返回内容压缩编码类型。 | Accept-Encoding: compress, gzip |
Accept-Language | 浏览器可接受的语言 | Accept-Language: en,zh |
Accept-Ranges | 可以请求网页实体的一个或者多个子范围字段 | Accept-Ranges: bytes |
Authorization | HTTP授权的授权证书 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Cache-Control | 指定请求和响应遵循的缓存机制 | Cache-Control: no-cache |
Connection | 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) | Connection: close |
Cookie | HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 | Cookie: $Version=1; Skin=new; |
Content-Length | 请求的内容长度 | Content-Length: 348 |
Content-Type | 请求的与实体对应的MIME信息 | Content-Type: application/ |
Date | 请求发送的日期和时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
Expect | 请求的特定的服务器行为 | Expect: 100-continue |
From | 发出请求的用户的Email | From: user@email.com |
Host | 指定请求的服务器的域名和端口号 | Host: www.zcmhi.com |
If-Match | 只有请求内容与实体相匹配才有效 | If-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Modified-Since | 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 | If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
If-None-Match | 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 | If-None-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Range | 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag | If-Range: “737060cd8c284d8af7ad3082f209582d” |
If-Unmodified-Since | 只在实体在指定时间之后未被修改才请求成功 | If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
Max-Forwards | 限制信息通过代理和网关传送的时间 | Max-Forwards: 10 |
Pragma | 用来包含实现特定的指令 | Pragma: no-cache |
Proxy-Authorization | 连接到代理的授权证书 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Range | 只请求实体的一部分,指定范围 | Range: bytes=500-999 |
Referer | 先前网页的地址,当前请求网页紧随其后,即来路 | Referer: http://www.zcmhi.com/archives… |
TE | 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 | TE: trailers,deflate;q=0.5 |
Upgrade | 向服务器指定某种传输协议以便服务器进行转换(如果支持) | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
User-Agent | User-Agent的内容包含发出请求的用户信息 | User-Agent: Mozilla/5.0 (Linux; X11) |
Via | 通知中间网关或代理服务器地址,通信协议 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 关于消息实体的警告信息 | Warn: 199 Miscellaneous warning |
请求体
响应报文
- 响应报文
名称 | 组成 |
---|---|
状态行 | 状态码如 200、协议版本等 |
响应头 | 即返回的 header |
响应体 | 响应的正文数据 |
常见状态码
2XX 成功
- 200 OK,表示从客户端发来的请求在服务器端被正确处理
- 204 No content,表示请求成功,但响应报文不含实体的主体部分
- 206 Partial Content,进行范围请求
3XX 重定向
- 301 moved permanently,永久性重定向,表示资源已被分配了新的 URL
- 302 found,临时性重定向,表示资源临时被分配了新的 URL
- 303 see other,表示资源存在着另一个 URL,应使用 GET 方法丁香获取资源
- 304 not modified,表示服务器允许访问资源,但因发生请求未满足条件的情况
- 307 temporary redirect,临时重定向,和 302 含义相同
4XX 客户端错误
- 400 bad request,请求报文存在语法错误
- 401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息
- 403 forbidden,表示对请求资源的访问被服务器拒绝
- 404 not found,表示在服务器上没有找到请求的资源
5XX 服务器错误
- 500 internal sever error,表示服务器端在执行请求时发生了错误
- 503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求
响应头
缓存机制
- Cache-control 主要包含以下几个字段:
字段 | 说明 |
---|---|
private | 只有客户端可以缓存 |
public | 客户端和代理服务器都可以缓存 |
max-age | 缓存的过期时间 |
no-cache | 需要使用对比缓存来验证缓存数据,如果服务端确认资源没有更新,则返回304,取本地缓存即可,如果有更新,则返回最新的资源。做对比缓存与 Etag 有关。 |
no-store | 这个字段打开,则不会进行缓存,也不会取缓存 |
- Etag:当客户端发送第一次请求时服务端会下发当前请求资源的标识码 Etag ,下次再请求时,客户端则会通过 header 里的 If-None-Match 将这个标识码 Etag 带上,服务端将客户端传来的 Etag 与最新的资源 Etag 做对比,如果一样,则表示资源没有更新,返回304。
HTTP 1.1
对比 1.0,HTTP 1.1 主要区别主要体现在:
- 缓存处理:在 HTTP 1.0 中主要使用 header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP1.1 则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等更多可供选择的缓存头来控制缓存策略。
- 带宽优化及网络连接的使用:HTTP1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),避免带宽浪费。
- 错误通知管理:HTTP 1.1 新增了 24 个错误状态响应码,410(Gone)表示服务器上的某个资源被永久性的删除。
- Host 头处理:HTTP 1.1 的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
- 长连接:HTTP 1.1 支持长连接和请求的流水线理,在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection:keep-alive。
HTTP 2.0
Okhttp 支持配置使用 HTTP 2.0 协议,HTTP 2.0 相对于 Http1.x 来说提升是巨大的,主要有以下几点:
- 二进制格式:http1.x 是文本协议,而 http2.0 是二进制以帧为基本单位,是一个二进制协议,一帧中除了包含数据外同时还包含该帧的标识:Stream Identifier,即标识了该帧属于哪个 request,使得网络传输变得十分灵活。
- 多路复用:多个请求共用一个 TCP 连接,多个请求可以同时在这个 TCP 连接上并发,一个request 对应一个 id。
- header 压缩:HTTP2.0 使用 encoder 来减少需要传输的 header 大小,通讯双方各自cache一份 header fields 表,避免了重复传输,流量消耗,提高效率。
- 支持服务端推送
HTTPS
HTTP 的端口号是 80,HTTPS 是 443,HTTPS 需要到 CA 申请证书,一般免费证书很少,需要交费
SSL 的全称是 Secure Sockets Layer,即安全套接层协议,是为网络通信提供安全及数据完整性的一种安全协议。SSL协议在1994年被Netscape发明,后来各个浏览器均支持 SSL,其最新的版本是 3.0
TLS 的全称是 Transport Layer Security,即安全传输层协议,最新版本的 TLS是 IETF 制定的一种新的协议,它建立在 SSL 3.0 协议规范之上,是SSL 3.0的后续版本。在 TLS 与SSL 3.0 之间存在着显著的差别,主要是它们所支持的加密算法不同,所以 TLS 与 SSL3.0 不能互操作。虽然 TLS 与 SSL 3.0 在加密算法上不同,但在理解 HTTPS 的过程中,可以把 SSL 和 TLS 看做是同一个协议。
SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。
加密原理
HTTPS 为了兼顾安全与效率,同时使用了对称加密和非对称加密。数据是被对称加密传输的,对称加密过程需要客户端的一个密钥,为了确保能把该密钥安全传输到服务器端,采用非对称加密对该密钥进行加密传输,总的来说,对数据进行对称加密,对称加密所要使用的密钥通过非对称加密传输。
TCP/IP
IP(Internet Protocol)协议提供了主机和主机间的通信,为了完成不同主机的通信,我们需要某种方式来唯一标识一台主机,这个标识,就是著名的 IP 地址。通过IP地址,IP 协议就能够帮我们把一个数据包发送给对方。
TCP 的全称是 Transmission Control Protocol,TCP 协议在 IP 协议提供的主机间通信功能的基础上,完成这两个主机上进程对进程的通信。
三次握手
所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。
三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect() 时。将触发三次握手。
- 第一次握手(SYN=1, seq=x):
客户端发送一个 TCP 的 SYN 标志位置 1 的包,指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号 (Sequence Number) 字段里。
发送完毕后,客户端进入 SYN_SEND
状态。
- 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):
服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为 1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即 X+1。 发送完毕后,服务器端进入 SYN_RCVD
状态。
- 第三次握手(ACK=1,ACKnum=y+1)
客户端再次发送确认包(ACK),SYN 标志位为 0,ACK 标志位为 1,并且把服务器发来 ACK 的序号字段 +1,放在确定字段中发送给对方,并且在数据段放写 ISN 的 +1
发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手结束。
四次挥手
TCP 的连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),也叫做改进的三次握手。客户端或服务器均可主动发起挥手动作,在 socket 编程中,任何一方执行 close() 操作即可产生挥手操作。
- 第一次挥手(FIN=1,seq=x)
假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。
发送完毕后,客户端进入 FIN_WAIT_1 状态。
- 第二次挥手(ACK=1,ACKnum=x+1)
服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。
- 第三次挥手(FIN=1,seq=y)
服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。
发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。
- 第四次挥手(ACK=1,ACKnum=y+1)
客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。
服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。
客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。
TCP 与 UDP 的区别
区别点 | TCP | UDP |
---|---|---|
连接性 | 面向连接 | 无连接 |
可靠性 | 可靠 | 不可靠 |
有序性 | 有序 | 无序 |
面向 | 字节流 | 报文(保留报文的边界) |
有界性 | 有界 | 无界 |
流量控制 | 有(滑动窗口) | 无 |
拥塞控制 | 有(慢开始、拥塞避免、快重传、快恢复) | 无 |
传输速度 | 慢 | 快 |
量级 | 重量级 | 轻量级 |
双工性 | 全双工 | 一对一、一对多、多对一、多对多 |
头部 | 大(20-60 字节) | 小(8 字节) |
应用 | 文件传输、邮件传输、浏览器等 | 即时通讯、视频通话等 |
Socket
Socket 是一组操作 TCP/UDP 的 API,像 HttpURLConnection 和 Okhttp 这种涉及到比较底层的网络请求发送的,最终当然也都是通过 Socket 来进行网络请求连接发送,而像 Volley、Retrofit 则是更上层的封装。
使用示例
使用 socket 的步骤如下:
- 创建 ServerSocket 并监听客户连接;
- 使用 Socket 连接服务端;
- 通过 Socket.getInputStream()/getOutputStream() 获取输入输出流进行通信。
1 | public class EchoClient { |
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 nathanwriting@126.com