计算机网络

网络体系结构

为什么有网络体系结构以及如何通信

  • 为了降低网络设计的复杂性,绝大多数网络都组织成一个层次栈或分级栈
  • 其中,每一层都建立在下一层的基础之上,每一层的目的是想上一层提供特定的服务,而把如何实现这些服务的细节对上一层加以隐藏
  • 一台机器上的第n层与另一台机器上的第n层进行对话,该对话中使用的规则和约定统称为第n层协议,所谓协议,是指通信双方就如何通信的一种约定
  • 实际上,数据并不是从一台机器的第n层直接传递到另一台机器的第n层,相反,每一层都将数据和控制信息传递给它的下一层,这样一直传递到最低层
  • 层和协议的集合称为网络体系结构

层次设计问题

  • 可靠性:检错(从接收到的信息中发现错误)、路由(找到通过的工作路径)
  • 寻址与命名:分别在底层和高层中用来标识发送方和接收方的机制
  • 消息顺序:并非所有通信信道都能维持其上发送消息的顺序
  • 长度:网络能够传输的消息的最大长度存在差异
  • 流量控制:如何保持快速发送方不会用数据把慢速接收方淹没
  • 拥塞控制:即网络超载,太多计算机要发送太多的流量,而网络又没有能力传递所有的数据包

TCP 协议

传输控制协议(TCP, Transmission Control Protocol)是为了在不可靠的网络上提供可靠的端到端字节流的而专门设计的一个传输协议。

  • 所有TCP连接都是全双工的、点到点的。所谓全双工,意味着同时可在两个方向上传输数据;所谓点到点,则意味着每个连接恰好有两个端点。
  • 一个TCP连接就是一个字节流,而不是消息流。端到端之间不保留消息的边界。
  • TCP连接上的每个字节都有他自己独有的一个32位(4字节)的序号。
  • 发送端和接受端的TCP实体以段的形式交换数据。TCP段(TCP Segment)由一个固定20字节的头(加上可选部分)以及随后0个或多个数据字节构成。

TCP段的头

TCP头格式

下面是TCP段头各个部分的含义

  1. 源端口号和目的端口号,各占2字节,该字段标识了连接的本地端点,用于寻找发送端和接受端的进程。TCP端口加上主机的IP地址组成了48位的唯一端点(Socket);
  2. 序号,占4字节,该字段标识从发送端向接受端发送的字节流,其值为字节流的第一个字节对应的序号;
  3. 确认号,占4字节,该字段标识下一个期待的字节编号
  4. TCP首部长度,占4位,该字段指明了TCP头包含了多少个32位的字,也是数据部分在段内的起始位置(以32位字为单位)。若不存在这个部分,则长度为默认值20字节,最大值为60字节
  5. 保留,占4位,一般无意义
  6. 标志位,占8位
    URG(紧急) : 为1时表明紧急指针字段有效
    ACK(确认):为1时表明确认号字段有效
    PSH(推送):为1时接收方应尽快将这个报文段交给应用层
    RST(复位):为1时表明TCP连接出现故障必须重建连接
    SYN(同步):在连接建立时用来同步序号
    FIN (终止): 为1时表明发送端数据发送完毕要求释放连接
  7. 滑动窗口大小,占2字节,该字段指定了从被确认的字节算起可以发送多少个字节,被用于流量控制和拥塞控制
  8. 校验和,占2字节,该字段提供了额外的可靠性
  9. 选项,占0字节或4字节的倍数,该字段提供了一些额外信息,比如:最大段长,窗口尺度,时间戳,选择确认

最大段长(MSS, Maxium Segment Size),用于连接建立过程,每一端可以宣布它的最大段长,采用大的段通常更有效率,但是小型主机可能处理不了大的段

窗口尺度(Window Scale),用于滑动窗口大小字段的扩充,可将该字段向左移动至多14位,允许窗口最大可达 个字节

时间戳(Timestamp),主要用来计算来回时间样值,该样值被用在估算多久之后数据包可被认为丢失

选择确认(SACK, Selective ACKnowledgement),该选项使得接收端可以告诉发送端已经接收到端的序号范围,这是对确认号(Acknowlegement)的补充,可用在一个数据包一丢失但后续数据到达的特定情况

TCP三次握手

  1. 三次握手图
    TCP三次握手

  2. 原理

第一次握手:

  • 客户端向服务端发送SYN报文,并指明客户端的初始化序列号ISN
  • 客户端状态由Closed转变成SYN_SEND状态

首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但是要消耗掉一个序号

第二次握手:

  • 服务端收到从客户端发来的SYN报文后,会以自己的SYN报文作为应答,并指明服务端的初始化序列号ISN
  • 将客户端的ISN+1作为自己的ACK值,表示已经收到客户端的SYN报文
  • 服务端状态由LISTEN转变为SYN_RCID

在确认的报文段中,同步位SYN=1,确认位ACK=1,初始序号seq=y,确认号ack=x+1

第三次握手

  • 客户端收到从服务端发来的SYN报文后,会以自己的SYN报文作为应答
  • 将服务端的ISN+1作为自己的ACK值,表示已经收到服务端的SYN报文
  • 客户端状态由SYN_SEND转变为ESTABLISHED
  • 服务端收到ACK报文后,状态由SYN_RIVD转变为ESTABLISHED,此时双方已建立了连接

确认报文段中,确认位ACK=1,序号seq=x+1,ack=y+1,ACK报文段可携带数据,若不携带数据则不消耗序号

  1. 为什么需要三次握手,二次握手行吗
    我们从三次握手的目的出发:
  • 第一次握手:客户端发送网络包,服务端接收到了
    此时,服务端完成验证:客户端的发送能力、服务端的接收能力是正常的
  • 第二次握手:服务端发送网络包,客户端接收到了
    此时,客户端完成验证:客户端的发送能力、接收能力、服务端的发送能力、接收能力是正常的。但服务端还不确定客户端的接收能力、服务端的发送能力是否正常
  • 第三次握手:客户端发送网络包,服务端接收到了
    此时,服务端完成验证:客户端、服务端的发送/接收能力均正常。

若采用二次握手,则会出现下面的情况:

如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一致等待客户端发送数据,浪费资源。

  1. 连接队列
    服务端维护两个连接队列,分别为:半连接队列、全连接队列
    半连接队列:服务器第一次收到客户端发来的SYN数据报后,处于SYN_RCVD状态,此时双方还未完全建立连接,服务器会把此种状态下的的连接请求放在半连接队列里。

全连接队列:已经完成三次握手的连接放在全连接队列里。

  1. 初始序列值是固定的吗
    初始序列值用于:当一端为建立连接发送SYN数据包时,他为连接选择一个初始序号。这个初始序号是随时间变化的,像一个计数器一样,每4ms增加1。

  2. 三次握手中可以携带数据吗
    第三次可以,前两次不可以。若第一次握手可以携带数据的话,恶意的一方向服务器发送携带大量数据的SYN数据包,不停地发,这样会使得服务器花费很多的时间、空间来接收这些数据。而对于第三次可以发,是因为双方已经建立连接了。

  3. SYN泛洪攻击是什么
    服务端的资源是在建立连接的第二次握手时分配的(客户端是第三次握手时分配),若带有恶意的Client在短时间内伪造大量的IP地址,不断地向服务端发送SYN数据包的话,这些伪造的连接将抢占大量的半连接队列,从而导致正常的连接请求因为队列满了而丢弃

TCP 和 UDP 的区别

性质 TCP UDP
可靠性 可靠 不可靠
连接性 面向连接 无连接
报文 字节流 报文
效率 效率低 效率高
双工性 全双工 (一/多)对(一/多)
流量控制 滑动窗口
拥塞控制 慢开始、拥塞避免、快重传、快恢复
传输速度
应用场景 准确性>效率 效率>准确性