Skip to content

Latest commit

 

History

History
334 lines (259 loc) · 19.1 KB

计算机网络基础.md

File metadata and controls

334 lines (259 loc) · 19.1 KB

网络体系的分层结构

分层 说明
应用层(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() 获取输入输出流进行通信。
public class EchoClient {
 
    private final Socket mSocket;
 
    public EchoClient(String host, int port) throws IOException {
        // 创建 socket 并连接服务器
        mSocket = new Socket(host, port);
    }
 
    public void run() {
        // 和服务端进行通信
        Thread readerThread = new Thread(this::readResponse);
        readerThread.start();
 
        OutputStream out = mSocket.getOutputStream();
        byte[] buffer = new byte[1024];
        int n;
        while ((n = System.in.read(buffer)) > 0) {
            out.write(buffer, 0, n);
        }
    }

    private void readResponse() {
        try {
            InputStream in = mSocket.getInputStream();
            byte[] buffer = new byte[1024];
            int n;
            while ((n = in.read(buffer)) > 0) {
                System.out.write(buffer, 0, n);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
 
    public static void main(String[] argv) {
        try {
            // 由于服务端运行在同一主机,这里我们使用 localhost
            EchoClient client = new EchoClient("localhost", 9877);
            client.run();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}