计算机网络

Posted by 石坤 on 2019-01-01

网络

1. 基础

各层协议的作用, 以及TCP/IP协议的特点

1. 五层协议
  • 运用层: 为特定的程序提供数据传输服务, 比如HTTP, DNS, 数据单位为报文
  • 传输层: 为进程提供通用数据传输服务. 运输层包括两种协议:TCP 与 UDP
  • 网络层: 为主机提供数据传输服务. 而传输层协议是为主机中的进程提供提供数据传输服务. 网络层把传输层传递下来的报文段或者用户数据报封装成分组
  • 数据链路层: 网络层针对的还是主机之间的数据传输服务, 而主机之间可以有很多链接, 链路层协议就是为同一链路的主机提供数据传输服务. 数据链路层把网络层传下来的分组封装成帧
  • 物理层: 考虑的是怎样在传输传输媒体上传输数据比特流, 而不是具体的传输媒体. 物理层的作用是尽可能屏蔽传输媒体和通信手段的差异, 使数据链路层感觉不到这些差异
2. OSI
  • 表示层: 数据压缩, 加密以及数据描述, 这使得应用程序不必关心在各台主机中数据内部格式不同的问题
  • 会话层: 建立及管理会话
3. TCP/IP协议

将五层协议中的数据链路层和物理层合并为网络接口层

TCP/IP体系结构不严格遵循OSI分层概念, 应用层可能会直接使用IP层或网络接口层.

4. 数据在各层之间的传递过程

在向下的过程中, 需要添加下层协议所需要的首部或者尾部, 而在向下的过程中不断拆开首部和尾部

路由器只有下面三层协议, 因为路由器位于网络核心中, 不需要为进程或者应用程序提供服务, 因此也就不需要传输层和应用层

UPD与TCP比较, 分析上层协议应该使用UDP还是TCP

  • 传输控制协议TCP, 提供面向连接, 可靠的数据传输服务, 数据单位为报文段; 提供可靠交付, 有流量控制, 拥塞控制, 提供全双工同学, 面向字节流(把应用层传下来的报文看成字节流, 把字节流组织成大小不等的数据块), 每一条TCP连接只能是点对点的(一对一)

  • 用户数据报协议UDP, 提供无连接, 尽最大努力的数据传输服务, 数据单位为用户数据报; 没有拥塞控制, 面向报文(对于应用程序传下来的报文不合并也不拆分, 只是添加UDP首部), 支持一对一, 一对多, 多对一, 多对多的交互通信.

TCP主要提供完整性服务, UDP主要提供及时性服务.

理解三次握手以及四次挥手具体过程, 三次握手的原因, 四次挥手原因, TIME_WAIT的作用

TCP的三次握手

假设A为客户端, B为服务器端.

  • B处于监听状态, 等待客户端的请求
  • A向B发送请求报文, SYN=1, ACK=0, 选择一初始序号x
  • B收到请求报文, 如果同意建立连接, 想A发送连接确认报文, SYN=1, ACK=1, 确认号为x+1, 同时也选择一个初始的序号y
  • A收到B的连接确认报文后, 还要想B发出确认, 确认号为y+1, 序号为x+1
  • B收到A的确认后, 连接建立
三次握手的原因

第三次握手是为了防止失效的连接请求到达服务器, 让服务器错误打开连接

TCP的四次挥手
  • A发送连接释放报文, FIN=1
  • B收到后发送确认, 此时TCP属于半关闭状态, B能想A发送数据但是A不能向B发送数据
  • 当B不再需要连接时, 发送连接释放报文, FIN=1
  • A收到后发出确认, 进入TIME-WAIT状态, 等待2MSL(最大报文存活时间)后释放连接
  • B收到A的确认后释放连接
四次挥手的原因

客户端发送了FIN连接释放报文后, 服务器收到了这个报文, 就进入了CLOSE-WAIT状态, 这个状态是为了让服务器发送还未传送完毕的数据, 传送完毕之后, 服务器会发送FIN连接释放报文

TIME_WAIT

客户端接收到服务器端的FIN报文后进入此状态, 此时并不是直接进入CLOSED状态, 还需要等待一个时间计时器设置的时间2MSL. 这么做有两个理由:

  • 确保最后一个确认报文能够到达. 如果B没收到A发送来的确认报文, 那么就会重新发送连接释放请求报文, A等待一段时间就是为了处理这种情况的发生
  • 等待一段时间是为了让本连接持续时间内所有产生的报名都从网络中消失, 使得下一次新的连接不会出现旧的连接请求报文.

可靠传输原理, 并设计可靠UDP协议

TCP使用超时重传来实现可靠传输: 如果一个已经发送的报文段在超时时间内没有收到确认, 那么就重传这个报文段. (实现方法: 确认机制, 重传机制, 滑动窗口)

一个报文段从发送再到接收到确认所经过的试产称为往返时间RTT.

最简单的方式是在应用层模仿传输层TCP的可靠性传输。下面不考虑拥塞处理,可靠UDP的简单设计。

  • 1、添加seq/ack机制,确保数据发送到对端
  • 2、添加发送和接收缓冲区,主要是用户超时重传。
  • 3、添加超时重传机制。

详细说明:送端发送数据时,生成一个随机seq=x,然后每一片按照数据大小分配seq。数据到达接收端后接收端放入缓存,并发送一个ack=x的包,表示对方已经收到了数据。发送端收到了ack包后,删除缓冲区对应的数据。时间到后,定时任务检查是否需要重传数据。

目前有如下开源程序利用udp实现了可靠的数据传输。分别为RUDP、RTP、UDT

2.HTTP

GET与POST比较: 作用, 参数, 安全性, 幂等性, 可缓存

作用

GET用于获取资源, POST用于传输实体主体

参数

GET的参数时出现在URL中, 而POST的参数存在实体主体中.

因为URL只支持ASCII码, 所以GET的参数中如果存在中文等字符需要先进行编码. 比如, 空格会转化为%20

安全

安全的HTTP方法值得是不改变服务器状态, 不修改数据, 也就是说它只是可读的.

GET方法是安全的, 而POST却不是. 因为POST的目的是传送实体主体内容, 这个内容可能是用户上传的表单数据, 上传成功后, 服务器可能把这个数据存储在数据库中, 因此状态发生了改变

不安全的方法除了POST还有: PUT, DELETE

安全的方法包括GET, HEAD, OPTIONS

幂等性

幂等性指的是同样的请求被执行一次与连续执行多次的效果是一样的, 服务器的状态也是一样的.

在正确的实现在, GET, HEAD, PUT和DELETE等方法都是幂等的, 而POST方法不是.

可缓存

如果要对相应进行缓存, 需要满足以下条件:

  • 请求报文的HTTP方法本身是可缓存的, 包括GET, HEAD, 但是PUT和DELETE不可缓存, POST多数情况下不可缓存
  • 响应报文的状态码是可缓存的. 包括: 200, 300, 404, 501等
  • 响应报文的Cache-Control首部字段没有指定不进行缓存
XMLHttpRequest
XMLHttpRequest是一个API, 它为客户端提供了再客户端和服务器之间传输数据的功能. 在AJAX中被大量使用.

在使用XMLHttpRequest的POST方法中, 浏览器会先发送Header再发送Data, 但不是所有的浏览器都会这么做, 比如火狐就不会

而GET方法Header和Data会一起发送

Cookie作用, 安全性问题, 和Session的比较

Cookie是服务器发送到用户浏览器并保存到本地的一小块数据, 他会在浏览器之后想同一服务器再次发起请求时被携带上, 用于告诉服务器两个请求是否来自于同一个浏览器.

作用:
  • 会话状态管理(用户登录状态等)
  • 个性化设置(用户自定义设置)
  • 浏览器行为跟踪(跟踪分析用户行为)
安全性问题
  • 标记为Secure的Cookie只能通过被HTTPS协议加密过的请求发送给服务端. 但即便设置了Secure标记, 敏感信息也不应该通过Cookie传输, 因为Cookie有其固有的不安全性.
Session

除了可以将用户信息通过Cookie存在用户浏览器, 也可以利用Session存储在服务器端, 存储在服务器端的信息更加安全.

Session可以存储在服务器上的文件, 数据库或者内存中. 也可以将Session存在Redis这种内存型数据库中, 效率会更高.

使用Session维护用户登录状态的过程:

  • 用户登录时, 把用户提交的用户名和密码放入HTTP请求报文中
  • 服务器验证用户名和密码, 如果正确, 则把用户信息存在Redis中, 它在Redis中的Key称为Session ID.
  • 服务器返回的响应报文的Set-Cookie首部字段包含了这个Session ID, 客户端收到响应报文后提取出Session ID, 从Redis中取出用户信息, 继续之前的业务操作

应该注意Session ID 的安全性问题, 不能让它被恶意攻击者轻易获取, 那么就不能产生一个容易被猜到的Session ID值. 此外, 还需要经常重新生成 Session ID. 在对安全性要求的场景下, 例如转账等操作, 除了使用Session管理用户状态之外, 还需要对用户进行重新验证, 比如重新输入密码, 或者使用短信验证码等方式

Cookie与Session比较
  • Cookie只能存储ASCII吗字符串, 而Session可以存取任何类型的数据, 所以数据比较复杂时首先Session
  • Cookie存在浏览器中, 容易被恶意查看, 不安全. 如果非要将隐私数据存在Cookie中, 可以将Cookie值加密, 然后在服务器中解密
  • 对于大型网站, 如果用户所有信息都存在Session中, 那么开销是非常大的, 所以不建议将所有用户信息都存在Session中

长连接与短连接原理以及使用场景, 流水线

当浏览器访问一个包含多张图片的HTML页面时, 除了请求访问HTML页面资源, 还会请求图片资源. 如果每进行一次HTTP通信就要新建一个TCP连接, 那么开销会很大.

长连接只需要建立一次TCP连接就能进行多次HTTP通信.

HTTP/1.1之后, 默认为长连接, 如果要断开连接, 需要使用Connection: close;

流水线

默认情况下, HTTP是按顺序发出的, 下一次请求只有在当前请求收到相应之后才会被发出. 由于会受到网络延迟和带宽的限制, 在下一个请求被发送到服务器之前, 可能需要等待很长时间.

流水线是在同一条长连接上发出连续的请求, 而不用等待相应返回, 这样可以避免连接延迟.

HTTP存在的安全性问题, 以及HTTPs的加密, 认证和完整性保护作用

HTTP有以下安全性问题
  • 使用明文进行通信, 内容可能会被窃听
  • 不验证通信方的身份, 通信方的身份有可能遭遇伪装
  • 无法证明报文的完整性, 报文有可能遭篡改
HTTPs

HTTPs并不是新协议, 而是让HTTP先和SSL(Secure Sockets Layer)通信, 再由SSL和TCP通信, 也就是说HTTPs使用了隧道进行通信.

通过使用SSL, HTTPs具有了加密(防窃听), 认证(防伪装)和完整性保护(防篡改)

HTTPs采用混合的加密机制, 使用非对称秘钥加密用于传输对称秘钥来保证传输过程的安全性, 之后使用对称秘钥加密进行通信来保证通信过程的效率.

HTTps通过使用证书来对通信方进行认证.

SSL提供报文摘要功能来进行完整性保护

HTTP/1.1的特性

  • 默认为长连接
  • 支持流水线
  • 支持同时打开多个TCP连接
  • 支持虚拟主机
  • 新增状态码100
  • 支持分块传输编码
  • 新增缓存处理指令max-age

3.Socket

select, poll, epoll的原理, 比较, 以及使用场景; epoll的水平触发与边缘触发

https://segmentfault.com/a/1190000003063859

select/poll/epoll都是 I/O 多路复用的具体实现, select 出现的最早, 之后是 poll, 再是 epoll.

应用场景

很容易产生一种错觉认为只要用 epoll 就可以了,select 和 poll 都已经过时了,其实它们都有各自的使用场景。

1. select 应用场景

select 的 timeout 参数精度为 1ns,而 poll 和 epoll 为 1ms,因此 select 更加适用于实时性要求比较高的场景,比如核反应堆的控制。

select 可移植性更好,几乎被所有主流平台所支持。

2. poll 应用场景

poll 没有最大描述符数量的限制,如果平台支持并且对实时性要求不高,应该使用 poll 而不是 select。

3. epoll 应用场景

只需要运行在 Linux 平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接。

需要同时监控小于 1000 个描述符,就没有必要使用 epoll,因为这个应用场景下并不能体现 epoll 的优势。

需要监控的描述符状态变化多,而且都是非常短暂的,也没有必要使用 epoll。因为 epoll 中的所有描述符都存储在内核中,造成每次需要对描述符的状态改变都需要通过 epoll_ctl() 进行系统调用,频繁系统调用降低效率。并且 epoll 的描述符存储在内核,不容易调试。

Unix有五种 I/O 模型:

  • 阻塞式 I/O

应用进程被阻塞, 直到数据复制到应用进程缓存区中才返回

  • 非阻塞试 I/O

应用进程执行系统调用后, 内核返回一个错误码. 应用进程可以继续执行, 但是需要不断的执行系统调用来获知 I/O 是否完成, 这种方式成为轮询(polling)

  • I/O 复用(select 和 poll)

使用select或者poll等待数据, 并且可以等待多个套接字中的任何一个变为可读. 这一过程会被阻塞, 当某一个套接字可读时返回, 之后再石笋recvfrom 把数据从内核复制到进程中.

它可以让单个进程具有处理多个I/O事件的能力. 又称为Event Driven I/O, 即事件驱动 I/O

select/epoll的好处就在于单个process就可以同时处理多个网络连接的I/O. 它的基本原理就是select, poll, epoll这个function会不断的轮询所负责的所有socket, 当某个socket有数据到达了, 就通知用户进程.

I/O 多路复用的特点是通过一种机制一个进程能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select()函数就可以返回。

如果一个web服务器没有I/O复用, 那么每一个Socket连接都需要创建一个线程去处理. 如果同时有几万个连接, 那么就需要创建相同数量的线程. 相比于多进程和多线程技术, I/O 复用不需要进程线程创建和切换的开销, 系统开销更小

  • 信号驱动式 I/O (SIGIO)

应用进程使用sigaction系统调用, 内核立即返回, 应用进程可以继续执行. 内核在数据到达时向应用进程发送SIGIO信号, 应用进程收到之后在信号处理程序中条用recvfrom将数据从内核复制到应用进程中.

  • 异步 I/O(AIO)

应用进程执行aio_read系统调用会立即返回, 应用进程可以继续执行, 不会被阻塞, 内核会在所以操作完成之后向应用进程发送信号.

异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。