计算机网络

[TOC]

网络协议分层

国际标准化组织 ISO 提出了 OSI 开放互连的七层计算机网络模型,从上到下分别是应用层、表示层、会话层、运输层、网络层、链路层和物理层。OSI 模型的概念清楚,理论也比较完善,但是既复杂又不实用。还有一种是 TCP/IP 体系结构,它分为四层,从上到下分别是应用层、运输层、网际层和网络接口层,不过从实质上将只有三层,因为最下面的网络接口层并没有什么具体内容。因特网的协议栈使用一种五层的模型结构,从上到下依次是应用层、运输层、网络层、链路层和物理层,其中下层是为上层提供服务的,每层执行某些动作或使用下层的服务来提高服务。

应用层

应用层是网络体系结构中的最高层,应用层的任务就是通过应用进程之间的交互来完成特定网络应用,这一层的数据单元叫做报文

应用层的协议定义了应用进程之间通信和交互的规则,主要包括了域名系统 DNS、支持万维网的 HTTP 协议、支持电子邮件的 SMTP 协议、文件传输协议 FTP 等。

域名解析系统 DNS

DNS 被设计为一个联机分布式数据库系统,并采用客户服务器方式。DNS 使大多数名字都在本地进行解析,仅少量解析需要在互联网上通信,因此 DNS 的效率很高。由于 DNS 是分布式系统,即使单个计算机出现了故障也不会妨碍到整个 DNS 系统的正常运行。


主机向本地域名服务器的查询一般都是采用递归查询。本地域名服务器向根域名服务器的查询的迭代查询。

递归

在该模式下DNS 服务器接收到客户机请求,必须使用一个准确的查询结果回复客户机。如果DNS 服务器本地没有存储查询DNS 信息,那么该服务器会询问其他服务器,并将返回的查询结果提交给客户机。

迭代

这里写图片描述

DNS 服务器并不直接回复查询结果,而是告诉客户机另一台DNS 服务器地址,客户机再向这台DNS 服务器提交请求,依次循环直到返回查询的结果

image-20210329083541902

文件传送协议 FTP

FTP 使用 TCP 可靠的运输服务,FTP 使用客户服务器方式,一个 FTP 服务器进程可以同时为多个客户进程提供服务,在进行文件传输时,FTP 的客户和服务器之间要建立两个并行的 TCP 连接:控制连接和数据连接,实际用于传输文件的是数据连接。

电子邮件系统协议 SMTP/POP3/IMAP

一个电子邮件系统有三个主要组成构件,即用户代理、邮件服务器、以及邮件协议。

从用户代理把邮件传送到邮件服务器,以及在邮件服务器之间的传送都要使用 SMTP,但用户代理从邮件服务器读取邮件时则要使用 POP3 或 IMAP 协议。

基于万维网的电子邮件使用户可以利用浏览器收发电子邮件,用户浏览器和邮件服务器之间使用 HTTP 协议,而邮件服务器之间的传送仍然使用 SMTP 协议。

DHCP (Dynamic Host Configuration Protocol) 动态主机配置协议

提供了即插即用的连网方式,用户不再需要手动配置 IP 地址等信息。

DHCP 配置的内容不仅是 IP 地址,还包括子网掩码、网关 IP 地址。

  1. 客户端发送 Discover 报文,该报文的目的地址为 255.255.255.255:67,源地址为 0.0.0.0:68,被放入 UDP中,该报文被广播到同一个子网的所有主机上。如果客户端和 DHCP 服务器不在同一个子网,就需要使用中继代理。
  2. DHCP 服务器收到 Discover 报文之后,发送 Offer 报文给客户端,该报文包含了客户端所需要的信息。因为客户端可能收到多个 DHCP 服务器提供的信息,因此客户端需要进行选择。如果客户端选择了某个 DHCP 服务器提供的信息,那么就发送 Request 报文给该 DHCP 服务器。DHCP 服务器发送 Ack 报文,表示客户端此时可以使用提供给它的信息。

子网掩码的作用

子网掩码的作用:

1、用于将一个大的IP网络划分为若干小的子网络:

因为随着互联网的发展,越来越多的网络产生,有的网络多则几百台,有的只有区区几台,这样就浪费了很多IP地址,所以要划分子网。使用子网可以提高网络应用的效率。

2、用于屏蔽IP地址的一部分以区别网络标识和主机标识,并说明该IP地址是在局域网上,还是在远程网上:


运输层

运输层的任务就是负责向两台主机中进程之间的通信提供通用的数据传输服务,应用进程利用该服务来传送应用层报文。由于一台主机同时可以运行多个进程,因此运输层具有复用和分用的功能,复用就是多个应用层进程可以同时使用下面运输层的服务,分用就是把运输层收到的信息分别交付给上面应用层中的对应进程。

运输层主要使用两种协议:① 用户数据报协议 UDP,这是一种提供无连接的、尽最大努力交付的数据传输服务,不保证数据传输的可靠性,数据传输单位是用户数据报。② 传输控制协议 TCP,这是一种面向连接的、可靠的数据传输服务,数据传输单元是报文。


网络层

网络层负责为分组交换网上的不同主机提供通信服务,在发生数据时,网络层把数据层产生的报文或用户数据报封装成分组进行传送,由于网络层使用 IP 协议,因此分组也叫 IP 数据报。网络层的另一个任务就是选择合适的路由,使源主机运输层所传下来的分组能够通过网络中的路由器找到目的主机。

网络层的协议包括了网际协议 IP、地址解析协议 ARP、网际控制报文协议 ICMP 以及路由选择协议 RIP/OSPF/BGP-4 等。

网际协议 IP

网际协议 IP 是 TCP/IP 体系中两个最主要的协议之一,一般指的是 IPv4。与 IP 协议配套使用的协议还有 ARP、ICMP 和 IGMP,IP 使用 ARP,ICMP 和 IGMP 要使用 IP。由于网际协议 IP 是用来使互连起来的许多计算机网络能够进行通信的,因此 TCP/IP 体系中的网络层也称网际层或 IP 层。要解决 IP 地址耗尽的问题,根本方法是采用具有更大地址空间的新版本 IP 协议即 IPv6,向 IPv6 过渡可以使用双协议栈或使用隧道技术。

地址解析协议 ARP

由于 IP 协议使用了 ARP 协议,因此把 ARP 协议归到网络层,但 ARP 的作用是通过一个 ARP 高速缓存存储本地局域网的各主机和路由器的 IP 地址到硬件地址的映射表,以从网络层的 IP 地址解析出在数据链路层使用的硬件地址,因此也可以把 ARP 划归在数据链路层。与 ARP 对应的协议是 RARP,逆地址解析协议,作用是使只知道自己硬件地址的主机能够找出 IP 地址,但被 DHCP 协议取代。

路由选择协议 RIP/OSPF/BGP-4

路由选择协议有两大类:内部网关协议,如 RIP 和 OSPF;外部网关协议,如 BGP-4。

RIP 是分布式的基于距离向量的路由选择协议,只适用于小型互联网。RIP 按照固定的时间间隔与相邻路由器交换信息,交换的信息是当前路由表。OSPF 是分布式的链路状态协议,适用于大型互联网,只在链路状态发生变化时才向本自治系统中的所有路由器用洪泛法发送与本路由器相邻的所有路由器的链路状态信息。

BGP-4 是不同自治系统的路由器之间交换路由信息的协议,是一种路径向量路由选择协议。其目标是寻找一条能够到达目的网络且比较好的路由而不是最佳路由。

网际控制报文协议 ICMP

ICMP 报文作为 IP 数据报的数据,加上首部后组成 IP 数据报发送出去,使用 ICMP 并非为了实现可靠传输,ICMP 允许主机或路由器报告差错情况和提供有关异常情况的报告。ICMP 报文的种类有两种,即 ICMP 差错报告报文和 ICMP 询问报文。

ICMP 的一个重要应用就是分组间探测 PING,用来测试两台主机之间的连通性,PING 使用了 ICMP 回送请求与回送回答报文。

Ping

Ping 是 ICMP 的一个重要应用,主要用来测试两台主机之间的连通性。

Ping 的原理是通过向目的主机发送 ICMP Echo 请求报文,目的主机收到之后会发送 Echo 回答报文。Ping 会根据时间和成功响应的次数估算出数据包往返时间以及丢包率。

在规定的时候间内,源主机如果没有接到 ICMP 的应答包,则说明目标主机不可达;如果接收到了 ICMP 应答包,则说明目标主机可达。应答数据包的类型字段为 0,构建新的ICMP数据包,发回给主机A,此时,源主机会检查,用当前时刻减去该数据包最初从源主机上发出的时刻,就是 ICMP 数据包的时间延迟。

Traceroute
Traceroute 发送的 IP 数据报封装的是无法交付的 UDP 用户数据报,并由目的主机发送终点不可达差错报告报文

  • Traceroute 的第一个作用就是故意设置特殊的 TTL,来追踪去往目的地时沿途经过的路由器。Traceroute 的参数指向某个目的 IP 地址,它会发送一个 UDP 的数据包。将TTL 设置成 1,也就是说一旦遇到一个路由器或者一个关卡,就表示它“牺牲”了。如果中间的路由器不止一个,当然碰到第一个就“牺牲”。于是,返回一个 ICMP 包,也就是网络差错包,类型是时间超时。接下来,将 TTL 设置为2.。。这样,Traceroute 就拿到了所有的路由器 IP。怎么知道 UDP 有没有到达目的主机呢?Traceroute 程序会发送一份 UDP 数据报给目的主机,但它会选择一个不可能的值作为 UDP 端口号(大于 30000)。当该数据报到达时,将使目的主机的 UDP 模块产生一份“端口不可达”错误 ICMP 报文。如果数据报没有到达,则可能是超时

  • Traceroute 还有一个作用是故意设置不分片,从而确定路径的 MTU。要做的工作首先是发送分组,并设置“不分片”标志。发送的第一个分组的长度正好与出口 MTU 相等。如果中间遇到窄的关口会被卡住,会发送 ICMP 网络差错包.

网际组管理协议 IGMP

IP 多播使用 IGMP 协议,IGMP 并非在互联网范围内对所有多播组成员进行管理,它不知道 IP 多播组包含的成员个数也不知道这些成员都分布在哪些网络上。

IGMP 协议是让连接在本地局域网上的多播路由器知道本局域网上是否有主机上的某个进程参加或推出了某个多播组。


链路层

数据链路层的任务是将网络层交下来的 IP 数据报组装成帧,在两个相邻结点之间的链路上传输帧,每一帧包括数据和必要的控制信息(同步信息、地址信息、差错控制等)。在接收数据时,控制信息使接收端能够知道一个帧从哪个比特开始到哪个比特结束,这样链路层就可以从帧中提取出数据部分上交给网络层。控制信息还使接收端能够检测到所收到的帧有无差错,如果有差错就简单地丢弃这个帧以免继续传送而浪费网络资源。

数据链路层的协议包括了点对点协议 PPP 和 CSMA/CD 协议等。

点对点协议 PPP

在通信线路质量较差的年代,使用高级数据链路控制 HDLC 作为实现可靠传输的数据链路层协议,但现在 HDLC 已经很少使用了,对于点对点的链路,简单得多的点对点协议 PPP 是目前使用得最广泛的数据链路层协议。PPP 协议的特点是简单、只检测差错而不纠正差错、不使用序号也不进行流量控制、可同时支持多种网络层协议。

CSMA/CD 协议

CSMA/CD 表示载波监听多点接入 / 碰撞检测。

  • 载波监听 :每个主机都必须不停地监听信道。在发送前,如果监听到信道正在使用,就必须等待。

  • 多点接入 :说明这是总线型网络,许多主机以多点的方式连接到总线上。

  • 碰撞检测 :在发送中,如果监听到信道已有其它主机正在发送数据,就表示发生了碰撞。虽然每个主机在发送数据之前都已经监听到信道为空闲,但是由于电磁波的传播时延的存在,还是有可能会发生碰撞。

记端到端的传播时延为 t,最先发送的站点最多经过 2t就可以知道是否发生了碰撞,称 2t 为 争用期 。只有经过争用期之后还没有检测到碰撞,才能肯定这次发送不会发生碰撞。

当发生碰撞时,站点要停止发送,等待一段时间再发送。这个时间采用 截断二进制指数退避算法 来确定。从离散的整数集合 {0, 1, .., (2^k-1)} 中随机取出一个数,记作 r,然后取 r 倍的争用期作为重传等待时间。


物理层

物理层的任务是尽可能地屏蔽掉传输媒体和通信手段的差异,使物理层上面的数据链路层感觉不到这些差异,使其只需考虑本层的协议和服务。

物理层所传输的数据单位是比特,发送方发送 1 或 0,接收方也接收 1 或 0,因此物理层需要考虑用多大的电压代表 1 或 0,以及接收方如何识别出发送方所发送的比特。除此之外,物理层还要确定连接电缆的插头应当有多少根引以及各引脚如何连接等问题。


表示层

数据压缩、加密以及数据描述,这使得应用程序不必关心在各台主机中数据内部格式不同的问题

会话层

建立及管理会话。

TCP

TCP 特点

TCP 是面向连接的运输层协议,一个应用进程在向另一个进程发送数据之前,两个进程必须先建立 TCP 连接,发送某些预备报文段,建立确保数据传输的参数。作为 TCP 连接建立的一部分,连接双方都将初始化与 TCP 连接相关的许多状态变量。这种连接不是电路交换网络中的端到端电路这种物理连接,而是一种逻辑连接,TCP 报文要先传送到 IP 层加上 IP 首部后,再传到数据链路层,加上链路层的首部和尾部后才离开主机发送到物理层。

TCP 连接提供全双工服务,允许通信双方的应用进程在任何时候都能发送数据。TCP 连接的两端都有各自的发送缓存和接收缓存,用来临时存放通信数据。在发送时,应用程序把数据传送给 TCP 缓存后就可以做自己的事,而 TCP 在合适的时候会把数据发送出去。在接收时,TCP 把收到的数据放入缓存,上层应用程序会在合适的时候读取缓存数据。

TCP 连接是点对点的,每一条 TCP 连接只能有两个端点,即只能是单个发送方和单个接收方之间的连接。

TCP 提供可靠的交付服务,通过 TCP 连接传送的数据无差错、不丢失、不重复,按序到达。

TCP 是面向字节流的,流是指流入到进程或从进程中流出的字节序列。面向字节流的含义是:虽然应用程序和 TCP 的交互是一次一个数据块,但是 TCP 把应用程序交下来的数据仅仅看成一连串无结构的字节流。TCP 不保证接收方应用程序收到的数据块和发送方应用程序发出的数据块具有对应大小的关系,但是接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。接收方应用程序必须有能力识别收到的字节流,并把它还原成有意义的应用层数据。


TCP 报文结构

img

TCP 传送的数据单元是报文段,一个 TCP 报文段分为首部和数据两部分。首部的前 20 个字节是固定的,后面有 4n 字节是根据需要而增加的选项,因此 TCP 首部的最小长度是 20 字节.TCP 首部的重要字段如下:

源端口和目的端口:各占 2 字节,分别写入源端口号和目的端口号,TCP 的分用功能是通过端口实现的,分用就是指运输层从 IP 层收到发送给各应用进程的数据后,把数据交付给正确的套接字的工作。

序号:占 4 字节。TCP 是面向字节流的,在一个 TCP 连接中传送的字节流中的每一个字节都按顺序编号,首部中的序号字段值指的是本报文段所发送的数据的第一个字节的序号。序号使用 mod2^32^ 计算,每增加到 2^31^-1 后下一个序号就又回到 0。

确认号:占 4 字节,是期望收到对方下一个报文段的第一个数据字节的序号。如果确认号为 N,代表到序号 N-1 为止的所有数据已经正确收到。序号有 32 位长,一般情况下可以保证当序号重复使用时,旧序号的数据早已通过网络到达终点了。

数据偏移:占 4 字节,实际是TCP 报文段的首部长度,指出了 TCP 报文段的数据起始处到 TCP 报文段的起始处的距离。由于首部中有长度不确定的选项字段,因此数据偏移字段是必要的。

标志字段:占 6 位。URG 是紧急标志,URG=1 时告诉系统此报文段中有紧急数据,应尽快传送,而不按照原来的排队顺序传送,和紧急指针配合使用,紧急指针指出了本报文段中紧急数据的字节数和位置。ACK 是确认标志,ACK=1 时表示成功接收了报文段。SYN 是同步标志,在建立连接时用来同步序号,当 SYN=1 而 ACK=0 时,表示一个连接请求报文段,响应时 SYN 和 ACK 都为 1,因此 SYN=1 表示一个连接请求或连接响应报文。FIN 是终止标志,用来释放一个连接,当 FIN=1 时表示报文段发送方的数据已发送完毕,并要求释放连接。PSH 是推送标志,PSH=1 时接收方就不等待整个缓存填满了再向上交付而是尽快交付数据。RST 是复位标志,当 RST=1 时表示 TCP 连接出现了严重错误,必须释放连接再重新建立连接。

接收窗口:占 2 字节,指的是发送本报文段一方的接收窗口,告诉对方从本报文首部的确认号算起允许对方发送的数据量。窗口值是用来限制发送方的发送窗口的,因为接收方的数据缓存空间是有限的。

检验和:占 2 字节,检验范围包括首部和数据两部分。在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部。


可靠传输协议 ARQ

自动重传请求 ARQ 包括了停止等待协议、回退 N 步协议和选择重传协议,后两种结合了窗口机制,属于连续 ARQ 协议。

停止等待协议

停止等待就是每发送完一个分组就停止发送,等待对方的确认,在收到确认之后再发送下一个分组。停止等待协议包括了三种情况:


回退 N 步协议

在回退 N 步即 GBN 协议中,允许发送方发送多个分组而不需要等待确认。

在 GBN 协议中,接收方丢弃所有失序分组,即使是正确接收的也要丢弃,这样做的理由是接收方必须按序将数据交付给上层。这种做法的优点是接收缓存简单,即接收方不需要缓存任何失序分组。不过丢弃一个正确失序分组的缺点是随后对该分组的重传也许也会错误,而导致更多的重传。


选择重传协议

选择重传即 SR 协议.失序分组将被缓存直到所有丢失分组都收到,这时才可以将一批分组按序交付上层。


TCP 可靠原理

TCP 的可靠传输包含很多机制,例如使用检验和来检测一个传输分组中的比特错误、使用定时器来用于超时重传一个分组、使用序号来检测丢失的分组和冗余副本、使用确认来告诉发送方确认的分组信息、使用否定确认来告诉发送方某个分组未被正确接收。

TCP 的发送方仅需维持已发送过但未被确认的字节的最小序号和下一个要发送的字节的序号,从这种角度看 TCP 更像一个 GBN 协议。但是 TCP 和 GBN 有一些显著的区别,许多 TCP 实现会将正确接收但失序的报文段缓存起来。当分组 n 丢失时,GBN 会重传 n 之后的所有分组,但是 TCP 至多只会重传分组 n。对 TCP 提出的一种修改意见是选择确认,它允许 TCP 接收方有选择地确认失序报文段,而不是累积地确认最后一个正确接收的有序报文段,从这个角度看 TCP 又像 SR 协议。因此 TCP 的差错恢复机制是一种 GBN 和 SR 的结合体

除此之外,TCP 还使用流量控制拥塞控制来保证可靠性。

滑动窗口

滑动窗口以字节为单位。发送端有一个发送窗口,窗口中的序号是允许发送的序号,窗口的后沿是已经发送并且确认的序号,窗口的前沿是不允许发送的序号。窗口的后沿可能不动(代表没有收到新的确认),也有可能前移(代表收到了新的确认),但是不会后移(不可能撤销已经确认的数据)。窗口的前沿一般是向前的,也有可能不动(表示没有收到新的请求或对方的接收窗口变小),也有可能收缩,但 TCP 强烈不建议这么做,因为发送端在收到通知前可能已经发送了很多数据,此时如果收缩窗口可能会产生错误。

滑动窗口的状态需要3个指针p1,p2 和 p3。p1 之前的序号表示已经发送并且确认的序号,p1p2 的序号表示已经发送但还没有确认的序号,p2p3 表示允许发送的序号,也叫可用窗口,p1~p3 表示发送窗口,p3 之后的序号表示不可发送的序号。

发送缓存用来暂时存放发送应用程序传给发送方 TCP 准备发送的数据和已经发送但还没确认的数据。接收缓存用来暂时存放按序到达的但尚未被应用程序读取的数据以及未按序到达的数据。

注意三点:① 发送窗口根据接收窗口设置,但并不总是一样大,还要根据网络的拥塞情况调整。② 对于不按序到达的数据,TCP 通常存放在接收窗口,等到字节流缺少的字节收到后再按序交付上层应用程序。③ 接收方必须有累积确认功能,可以减小传输开销,可以在合适的时候发送确认,也可以在自己有数据需要发送时捎带确认。但是接收方不能过分推迟发送确认,不能超过0.5秒。

流量控制

如果某个应用程序读取数据的速度较慢,而发送方发送得太多、太快,发送的数据就会很容易使连接的接收缓存溢出,TCP 为它的应用程序提供了流量控制以消除发送方使接收方缓存溢出的可能性。流量控制是一个速度匹配服务,即发送方的发送速率与接收方的应用程序读取速率相匹配。

TCP 通过让发送方维护一个接收窗口的变量来提供流量控制。通俗地说,接收窗口用于给发送方一个指示,该接收方还有多少可用的缓存空间,因此方法方的发送窗口不能超过接收方给出的接收窗口的数值。因为 TCP 是全双工通信,在连接两端的发送方都各自维护一个接收窗口。

当接收窗口 rwnd 减小到 0 时,就不再允许发送方发送数据了。但是可能存在一种情况,当发生了零窗口报文段不久后,发送方的接收缓存又有了一些存储空间,因此又发生了新的报文说明自己的接收窗口大小,但是这个报文可能会在传输过程中丢失。接收方就会一直等待发送方的非零窗口通知,而发送方也一直在等待接收方发送数组,形成一种死锁的状态。为了解决这个问题,TCP 为每一个连接设有一个持续计时器,只要 TCP 连接的一方收到对方的零窗口通知就启动该计时器,到期后发送一个零窗口探测报文,如果仍为 0 就重新设置计时器的时间,如果对方给出了新的窗口值就可以解决可能出现的死锁问题。

还有一种问题叫做糊涂窗口综合症,当接收方处理接收缓冲区数据很慢时,就会使应用进程间传送的有效数据很小, 极端情况下有效数据可能只有 1 字节但传输开销却有 40 字节(20字节的 IP 头以及 20 字节的 TCP 头) ,导致网络效率极低。为了解决这个问题,可以让接收方等待一段时间,使得接收缓存有足够的空间容纳一个最长报文段或者等到接收缓存已有一半的空闲空间。发送方也不要发送太小的报文,而是把数据积累成足够大的报文或达到接收方缓存空间的一半时才发送。

拥塞控制

网络中对资源需求超过了资源可用量的情况就叫做拥塞。当吞吐量明显小于理想的吞吐量时就出现了轻度拥塞,当吞吐量随着负载的增加反而下降时,网络就进入了拥塞状态。当吞吐量降为 0 时,网络已无法正常工作并陷入死锁状态。拥塞控制就是尽量减少注入网络的数据,减轻网络中的路由器和链路的负担。拥塞控制是一个全局性的问题,它涉及网络中的所有路由器和主机,而流量控制只是一个端到端的问题,是两个端点之间通信量的控制。

根据网络层是否为运输层拥塞控制提供显式帮助可以将拥塞控制的方法区分为两种:端到端拥塞控制和网络辅助的拥塞控制。TCP 使用端到端的拥塞控制,因为 IP 层不会向端系统提供显式的网络拥塞反馈。TCP 所采取的方法是让每一个发送方根据所感知到的网络拥塞程度来限制其向连接发送数据的速率。如果一个 TCP 发送方感知到它到目的地之间的路径上没什么拥塞则会增加发送速率,如果发送方感知到拥塞就会降低其发送速率。限制发送速率是通过拥塞窗口来实现的,它对发送方能向网络中发送流量的速率进行了限制。判断拥塞是通过超时或者连续接收到 3 个冗余 ACK 实现的。

TCP 的拥塞控制算法主要包括了慢启动、拥塞避免和快恢复。慢启动和拥塞避免是 TCP 的强制部分,差异在于对收到的 ACK 做出反应时 cwnd 增加的方式,慢启动比拥塞避免要更快地增加 cwnd 的长度。快恢复是推荐部分,对 TCP 发送方不是必需的。

1. 慢启动

在慢启动状态,拥塞窗口 cwnd 的值以一个 MSS 最大报文段开始并且每当传输的报文段首次被确认就增加一个 MSS。因此每经过一个 RTT 往返时间,拥塞窗口就会翻倍,发送速率也会翻倍。因此 TCP 的发送速率起始很慢,但是在慢启动阶段以指数增长。

结束慢启动有三种情况:① 如果存在一个超时指示的丢包事件,即发生了拥塞,TCP 发送方就会将 cwnd 设置为 1 并重新开始慢启动过程。它还将慢启动阈值设置为 cwnd/2,即检测到拥塞时将慢启动阈值设置为拥塞窗口的一半。② 当拥塞窗口达到慢启动阈值时就会结束慢启动而进入拥塞避免模式。③ 最后一种结束慢启动的方式是,如果检测到三个冗余的 ACK,TCP 就会执行快重传并进入快恢复状态。

2. 拥塞避免

一旦进入拥塞避免状态,cwnd 的值大约是上次遇到拥塞时的值的一半,即距离拥塞可能并不遥远。因此 TCP 无法再每经过一个 RTT 就将 cwnd 的值翻倍,而是采用一种较为保守的方法,每个 RTT 后只将 cwnd 的值增加一个 MSS。这能够以几种方式完成,一种通用的方法是发送方无论何时收到一个新的确认,都将 cwnd 增加一个 MSS。

当出现超时时,TCP 的拥塞避免和慢启动一样,cwnd 的值将被设置为 1,并且将慢启动阈值设置为 cwnd 的一半。

3. 快恢复

有时候个报文段丢失,而网络中并没有出现拥塞,如果使用慢启动算法就会降低传输效率。这时应该使用快重传来让发送方尽早知道出现了个别分组的丢失,快重传要求接收端不要等待自己发送数据时再捎带确认,而是要立即发送确认。即使收到了乱序的报文段后也要立即发出对已收到报文段的重复确认。当发送方连续收到三个冗余 ACK 后就知道出现了报文段丢失的情况,会立即重传并进入快恢复状态。

在快恢复中,会调整慢启动阈值为 cwnd 的一半,并进入拥塞避免状态。


TCP 连接和释放机制

三次握手

TCP 是全双工通信,任何一方都可以发起建立连接的请求,假设 A 是客户端,B 是服务器。

初始 A 和 B 均处于 CLOSED 状态,B 会创建传输进程控制块 TCB 并进入 LISTEND 状态,监听端口是否收到了 TCP 请求以便及时响应。

当 A 要发生数据时就向 B 发送一个连接请求报文,TCP 规定连接请求报文的 SYN=1,ACK=0,SYN 不可以携带数据,但要消耗一个序号,假设此时 A 发送的序号 seq 为 x。发送完之后 A 就进入了 SYN-SENT 同步已发送状态。

当 B 收到 A 的连接请求报文后,如果同意建立连接就会发送给 A 一个确认连接请求报文,其中 SYN=1,ACK=1,ack=x+1,seq=y,ack 的值为 A 发送的序号加 1,ACK 可以携带数据,如果不携带的话则不消耗序号。发送完之后,B进入 SYN-RCVD 同步已接收状态。

当 A 收到 B 的确认连接请求报文后,还要对该确认再进行一次确认,报文的 ACK=1,ack=y+1,seq=x+1,发送后 A 进入 ESTABLISHED 状态,当 B 接收到该报文后也进入 ESTABLISHED 状态,客户端会稍早于服务器端建立连接。

三次握手的原因主要有两个目的,信息对等和防止超时。

从信息对等的角度看,双方只有确定 4 类信息才能建立连接,即 A 和 B 分别确认自己和对方的发送和接收能力正常。在第二次握手后,从 B 的角度看还不能确定自己的发送能力和对方的接收能力,只有在第三次握手后才能确认。

三次握手也是防止失效连接突然到达导致脏连接,网络报文的生存时间往往会超过 TCP 请求超时时间,A 的某个超时连接请求可能会在双方释放连接之后到达 B,B 会误以为是 A 创建了新的连接请求,然后发送确认报文创建连接。因为 A 机器的状态不是 SYN_SENT,所以直接丢弃了 B 的确认数据。如果是两次握手,连接已经建立了,服务器资源被白白浪费。如果是三次握手,B 由于长时间没有收到确认信息,最终超时导致创建连接失败,因此不会出现脏连接。

四次挥手

当 A 已经没有要发送的数据时就会释放连接,会向 B 发送一个终止连接报文,其中 FIN=1,seq=u,u 的值为之前 A 发送的最后一个序号+1。发送完之后进入 FIN-WAIT-1 状态。

B 收到该报文后,发送给 A 一个确认报文,ACK=1,ack=u+1,seq=v,v 的值为 B 之前发送的最后一个序号+1。此时 A 进入了FIN-WAIT-2 状态,B 进入了 CLOSE-WAIT 状态,但连接并未完全释放,B 会通知高层的应用层结束 A 到 B 方向的连接,此时 TCP 处于半关闭状态。

当 B 发送完数据后准备释放连接时,就向 A 发送连接终止报文,FIN=1,同时还要重发ACK=1,ack=u+1,seq=w,seq 不是 v 的原因是在半关闭状态 B 可能又发送了一些数据,之后 B 进入 LAST-ACK 状态。

A 收到连接终止报文后还要再进行一次确认,确认报文中 ACK=1,ack=w+1,seq=u+1。发送完之后进入 TIME-WAIT 状态,等待 2MSL之后进入 CLOSED 状态,B 收到该确认后进入 CLOSED 状态,服务器端会稍早于客户端释放连接。

四次挥手的原因

tcp是全双工通信,服务端和客服端都能发送和接收数据。

tcp在断开连接时,需要服务端和客服端都确定对方将不再发送数据。

第1次挥手

由客户端向服务端发起,服务端收到信息后就能确定客户端已经停止发送数据。

第2次挥手

由服务端向客户端发起,客户端收到消息后就能确定服务端已经知道客户端不会再发送数据。

第3次握手

由服务端向客户端发起,客户端收到消息后就能确定服务端已经停止发送数据。

第4次挥手

由客户端向服务端发起,服务端收到信息后就能确定客户端已经知道服务端不会再发送数据。

为什么不是3次挥手

在客服端第1次挥手时,服务端可能还在发送数据。

所以第2次挥手和第3次挥手不能合并。

大量 TIME-WAIT 的原因、导致的问题、处理

在高并发短连接的 TCP 服务器上,服务器处理完请求后立刻主动正常关闭连接,这个场景下会出现大量 socket 处于 TIME-WAIT 状态。

TIME-WAIT 状态无法真正释放句柄资源,socket 使用的本地端口在默认情况下不能再被使用,会限制有效连接数量,成为性能瓶颈。

可以调小 tcp_fin_timeout 的值,将 tcp_tw_reuse 设为 1 开启重用,将 tcp_tw_recycle 设为 1 表示开启快速回收。


TCP 和 UDP 的区别

TCP 是面向连接的,而 UDP 是无连接的,发送数据之前不需要建立连接,减少了开销和发送数据之前的时延。

TCP 保证数据的可靠传输,UDP 使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态。

TCP 是面向字节流的,UDP 是面向报文的,发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文既不拆分也不合并,而是保留这些报文的边界。如果报文太长,IP 层在传送时可能需要分片,如果报文太短,会使 IP 数据报首部的相对长度太大,都会降低 IP 层的效率。

TCP 有拥塞控制,UDP 没有拥塞控制,因此网络中出现的拥塞不会降低源主机的发送速率。这对某些实时应用很重要,很多实时应用如 IP 电话、实时视频会议等要求源主机以恒定的速率发送数据,并且允许在网络发生拥塞时丢失一些数据,但却不允许网络有太大的时延,UDP 正好适合这种要求。

TCP 是点到点之间的一对一通信,UDP 支持一对一、一对多和多对多的交互通信。

UDP 的首部开销很小,只有 8 字节,相比 TCP 的 20 字节要短。

TCP和UDP的传送信息单位的区别?

16位源端口号+16位目的端口号+32位序号+32位确认号+4位头部长度(单位4字节)+6位保留+6个关键字(SYN,ACK,FIN)+16位窗口大小(指接收窗口)+16位校验和+16位紧急指针+最多40字节的选项;

首部字段只有 8 个字节,包括源端口、目的端口、长度、检验和。

TCP三次握手后,客户端网线断掉了,服务端会不会检测得到?还有,如果客户端此时再插上网线,还需要进行三次握手吗?

短时间不会的,具体可以参考tcp的保活机制,隔一段时间发一个保活探测报文,超过保活探测次数连接就会关闭,

如果四次挥手中的第二次挥手后,服务端又收到了客户端发来的数据,那么服务端会做什么?

为什么三次握手,返回时,ack 值是 seq 加 1?

假设对方接收到数据,比如sequence number = 1000,TCP Payload = 1000,数据第一个字节编号为1000,最后一个为1999,回应一个确认报文,确认号为2000,意味着编号2000前的字节接收完成,准备接收编号为2000及更多的数据

确认收到的序列,并且告诉发送端下一次发送的序列号从哪里开始(便于接收方对数据排序,便于选择重传)

大量TIME_WAIT?

  1. 作为服务器,短时间内关闭了大量的Client连接,就会造成服务器上出现大量的TIME_WAIT连接,占据大量的tuple /tApl/ ,严重消耗着服务器的资源,此时部分客户端就会显示连接不上
  2. 作为客户端,短时间内大量的短连接,会大量消耗的Client机器的端口,毕竟端口只有65535个,端口被耗尽了,后续就无法在发起新的连接了

解决方法:

  • 用负载均衡来抗这些高并发的短请求;

  • 服务器可以设置 SO_REUSEADDR 套接字选项来避免 TIME_WAIT状态,TIME_WAIT 状态可以通过优化服务器参数得到解决,因为发生TIME_WAIT的情况是服务器自己可控的,要么就是对方连接的异常,要么就是自己没有迅速回收资源,总之不是由于自己程序错误导致的

  • 强制关闭,发送 RST 包越过TIMEWAIT状态,直接进入CLOSED状态

  • 调整参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    net.ipv4.tcp_tw_reuse = 1
    表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;

    net.ipv4.tcp_tw_recycle = 1
    表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。

    系统tcp_timestamps缺省就是开启的,所以当tcp_tw_recycle被开启后,实际上这种行为就被激活了.如果服务器身处NAT环境,安全起见,通常要禁止tcp_tw_recycle,至于TIME_WAIT连接过多的问题,可以通过激活tcp_tw_reuse来缓解。

    net.ipv4.tcp_max_syn_backlog = 8192
    表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。

大量CLose-Wait?

通常,CLOSE_WAIT 状态在服务器停留时间很短,如果你发现大量的 CLOSE_WAIT 状态,那么就意味着被动关闭的一方没有及时发出 FIN 包,一般有如下几种可能:

  • 程序问题:如果代码层面忘记了 close 相应的 socket 连接,那么自然不会发出 FIN 包,从而导致 CLOSE_WAIT 累积;或者代码不严谨,出现死循环之类的问题,导致即便后面写了 close 也永远执行不到。
  • 响应太慢或者超时设置过小:如果连接双方不和谐,一方不耐烦直接 timeout,另一方却还在忙于耗时逻辑,就会导致 close 被延后。响应太慢是首要问题,不过换个角度看,也可能是 timeout 设置过小。

TCP粘包?

TCP粘包就是指发送方发送的若干包数据到达接收方时粘成了一包,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾。

原因

原因可能是发送方也可能是接收方造成的。

发送方原因:TCP默认使用Nagle算法,将多次间隔较小、数据量较小的数据,合并成一个数据量大的数据块,然后进行封包。

接收方原因:TCP将接收到的数据包保存在接收缓存里,然后应用程序主动从缓存读取收到的分组。这样一来,如果TCP接收数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个首尾相接粘到一起的包。

如果多个分组毫不相干,甚至是并列关系,那么这个时候就一定要处理粘包现象了。

处理方法:

最本质原因在与接收对等方无法分辨消息与消息之间的边界在哪,通过使用某种方案给出边界,例如:

  • 发送定长包。如果每个消息的大小都是一样的,那么在接收对等方只要累计接收数据,直到数据等于一个定长的数值就将它作为一个消息。
  • 包尾加上\r\n标记。FTP协议正是这么做的。但问题在于如果数据正文中也含有\r\n,则会误判为消息的边界。
  • 包头加上包体长度。包头是定长的4个字节,说明了包体的长度。接收对等方先接收包体长度,依据包体长度来接收包体。

三次握手最后一次丢失

如果最后一次ACK在网络中丢失,那么Server端(服务端)该TCP连接的状态仍为SYN_RECV,并且根据 TCP的超时重传机制依次等待3秒、6秒、12秒后重新发送 SYN+ACK 包,以便 Client重新发送ACK包

如果重发指定次数后,仍然未收到ACK应答,那么一段时间后,Server(服务端)自动关闭这个连接

但是Client(客户端)认为这个连接已经建立,如果Client向Server(服务端)发送数据,Server端(服务端)将以RST包(Reset,标示复位,用于异常的关闭连接)响应,此时,客户端知道第三次握手失败

为什么连接的时候是三次握手,关闭的时候却是四次握手?

  • 建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端
  • 关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以服务器可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接。因此,服务器ACK和FIN一般都会分开发送,从而导致多了一次

为什么TCP挥手每两次中间有一个 FIN-WAIT2等待时间?

  • 主动关闭的一端调用完close以后(即发FIN给被动关闭的一端, 并且收到其对FIN的确认ACK)则进入FIN_WAIT_2状态。如果这个时候因为网络突然断掉、被动关闭的一段宕机等原因,导致主动关闭的一端不能收到被动关闭的一端发来的FIN(防止对端不发送关闭连接的FIN包给本端),这个时候就需要FIN_WAIT_2定时器, 如果在该定时器超时的时候,还是没收到被动关闭一端发来的FIN,那么直接释放这个链接,进入CLOSE状态

IP

img

4位版本

目前协议版本号是4,因此IP有时也称作IPV4.

4位首部长度

首部长度指的是首部占32bit字的数目,包括任何选项。由于它是一个4比特字段,因此首部长度最长为60个字节。

服务类型(TOS)

服务类型字段包括一个3bit的优先权字段(现在已经被忽略),4bit的TOS子字段和1bit未用位必须置0。4bit的TOS分别代表:最小时延,最大吞吐量,最高可靠性和最小费用。4bit中只能置其中1比特。如果所有4bit均为0,那么就意味着是一般服务。

总长度

总长度字段是指整个IP数据报的长度,以字节为单位。利用首部长度和总长度字段,就可以知道IP数据报中数据内容的起始位置和长度。由于该字段长16bit,所以IP数据报最长可达65535字节。当数据报被分片时,该字段的值也随着变化。

标识字段

标识字段唯一地标识主机发送的每一份数据报。通常每发送一份报文它的值就会加1。

生存时间

TTL(time-to-live)生存时间字段设置了数据报可以经过的最多路由器数。它指定了数据报的生存时间。TTL的初始值由源主机设置(通常为 3 2或6 4),一旦经过一个处理它的路由器,它的值就减去 1。当该字段的值为 0时,数据报就被丢弃,并发送 ICMP 报文通知源主机。

首部检验和

首部检验和字段是根据 I P首部计算的检验和码。它不对首部后面的数据进行计算。 ICMP、IGMP、UDP和TCP在它们各自的首部中均含有同时覆盖首部和数据检验和码。

HTTP

HTTP 概况

HTTP 即超文本传输协议,是 Web 的应用层协议。HTTP 由两个程序实现,一个客户程序和一个服务器程序,客户程序和服务器程序运行在不同的端系统中,通过交换 HTTP 报文进行会话。HTTP 定义了这些报文的结构以及客户和服务器进行报文交换的方式,当用户请求一个 Web 页面时,浏览器向服务器发出对该页面中所包含对象的 HTTP 请求报文,服务器接收到请求并用包含这些对象的 HTTP 响应报文进行响应。

HTTP 使用 TCP 作为它的支撑运输协议,HTTP 客户首先发起一个与服务器的 TCP 连接,一旦连接建立,该浏览器和服务器进程就可以通过套接字访问 TCP。客户端的套接字接口是客户进程与 TCP 连接之间的门,服务器端的套接字接口则是服务器进程与 TCP 连接之间的门。客户向它的套接字接口发送 HTTP 请求报文并从它的套接字接口接收 HTTP 响应报文,类似的,服务器从它的套接字接口接收 HTTP 请求报文并向它的套接字接口发送 HTTP 响应报文。一旦客户向它的套接字接口发送一个 HTTP 请求报文,该报文就脱离了客户控制并进入 TCP 的控制,TCP 为 HTTP 提供可靠的数据传输服务,因此一个客户进程发出的每个 HTTP 请求报文最终都能完整地到达服务器,服务器进程发出地每个 HTTP 响应报文最终也可以完整地到达客户。这里体现了分层体系结构的优点,HTTP 协议不需要担心数据丢失,也不需要关注 TCP 从网络的数据丢失和乱序中如何恢复。

HTTP 是一种无状态的协议,服务器向客户发送被请求的文件,而不存储任何关于该客户的状态信息。假如某个客户在短时间内连续两次请求同一个对象,服务器并不会因为刚刚为该客户做出了响应就不再响应,而是重新进行响应。


HTTP 报文格式

HTTP 报文有两种,分为请求报文和响应报文。

请求报文

HTTP 请求报文的第一行叫做请求行,其后继的行叫做首部行。请求行有三个字段,包括方法、URL 和 HTTP 版本。方法包括了 GET、POST、HEAD、PUT 和 DELETE 等。绝大部分的 HTTP 请求报文使用 GET 方法,当使用 GET 方法时,在 URL 字段中会带有请求对象的标识。

首部行指明了对象所在的主机,其实已经存在 TCP 连接了,但是还需要首部行提供主机信息,这时 Web 代理高速缓存所要求的。通过包含 Connection:close 的首部行,可以告诉服务器不要麻烦地使用持续连接,它要求在发送完响应后就关闭连接。User-agent 可以用来指明用户代理,即向服务器发送请求的浏览器类型,服务器可以有效地为不同类型的用户代理发送实际相同对象的不同版本。

在首部行之后有一个空行,后面跟着的是实体。使用 GET 方法时实体为空,而使用 POST 方法时才会使用实体。当用户提交表单时,HTTP 客户通常使用 POST 方法,使用 POST 方法时用户仍可以向服务器请求一个 Web 页面,但 Web 页面的特定内容依赖于用户在表单字段中输入的内容。如果使用 POST 方法,则实体中包含的就是用户在表单字段的输入值。表单不是必须使用 POST 方法,也可以使用 GET。

HEAD 方法类似于 GET,当服务器收到一个使用 HEAD 方法的请求时,将会用一个 HTTP 报文进行响应,但是并不返回请求对象。通常开发者使用 HEAD 方法进行调试跟踪。PUT 方法常用于上传对象到指定的 Web 服务器上指定的目录,DELETE 方法允许用户或应用程序删除 Web 服务器上的对象。

响应报文

响应报文包括状态行、首部行和实体。状态行有三个字段,协议版本、状态码和对应的状态信息。实体是报文的主要部分,即所请求的对象本身。

服务器通过首部行来告诉浏览器一些信息。 Connection:close 可以告诉客户发送完报文后将关闭该 TCP 连接。Date 是首部行指示服务器发送响应报文的日期和时间,这个时间不是对象创建或修改的时间,而是服务器从它的文件系统中检索到该对象,将该对象插入响应报文并发送的时间。Server 指明了服务器的类型,类似于请求报文中的 User-agent

状态码及其相应的短语指示了请求的结果,一些常见的状态码和相关短语如下:

状态码 短语 含义
200 OK 成功响应
301 Moved Permanently 请求的对象已经被永久转移了,新的 URL 定义在响应报文的 Location 首部行,客户将自动获取新的 URL。
302 Found 与301类似,但资源只是临时被移动,客户端应继续使用原有 URL。
400 Bad Request 一个通用的差错代码,标识该请求不能被服务器理解。
401 Unauthorized 未认证,缺乏相关权限。
402 Payment Required 保留,将来使用
403 Forbidden 服务器理解客户端的请求,但是拒绝执行。
404 Not Found 被请求的文档不在服务器上,有可能因为请求 URL 出错。
405 Method Not Allowed 客户端中请求的方法被禁止,例如限制 POST 方式但使用了 GET 访问。
500 Internal Server Error 服务器内部错误,无法完成请求。
501 Not Implemented 服务器不支持请求的功能,无法完成请求。
502 Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应。
503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。
504 Gateway Timeout 充当网关或代理的服务器,未及时从远端服务器获取请求。
505 HTTP Version Not Supported 服务器不支持请求报文使用的 HTTP 协议版本。

输入一个 url 发生的事

① 分析 url

判断输入的 url 是否合法,如果不合法浏览器会使用默认的搜索引擎进行搜索。如果输入的是一个域名,默认会加上一个 http 前缀。

② DNS 查询

检查浏览器的 DNS 缓存,检查本地 hosts 文件的缓存,如果没有会向本地 DNS 服务器发送请求。

主机向本地 DNS 服务器发起请求是递归查询,如果找到则返回,否则会向根 DNS 查询。

根 DNS 查询是迭代查询,没有域名和 ip 的对应关系,而是告知可以查询的域名服务器地址。

本地 DNS 向得到的域名服务器发出请求,收到一个域名和 ip 关系,把结果返回给用户,并把结果保存到缓存中。

③ TCP 建立连接

拿到 ip 地址后,通过 TCP 的三次握手建立连接,按照协议规定的格式发送 HTTP 请求报文。

④ 处理请求

服务器收到 HTTP 请求报文后进行响应,主进程进行监听,创建子进程处理,先判断是否是重定向,如果是重定向则返回重定向地址。如果是静态资源则直接返回,否则通过 REST URL 在代码层面处理返回结果,最后返回 HTTP 响应报文。

⑤ 接收响应

浏览器收到 HTTP 响应报文后进行解析,首先查看响应报文在状态行的状态码,根据不同的状态码做不同的事,解析 HTML、CSS、JS 等文件。构建 DOM 树,渲染树,重绘,将像素发送 GPU 进行渲染,最后将渲染结果返回给用户并进行缓存。

⑥ TCP 断开连接

通过 TCP 的四次挥手断开连接,如果是 HTTP1.1 则会将连接保持一小段时间。


HTTPS

  • 浏览器向服务器发起一个请求,服务器返回一个SSL证书
  • 首先浏览器读取证书中的证书所有者、有效期等进行一一校验
  • 浏览器开始查找操作系统中内置的受信任的证书发布机构CA,与服务器发来的证书中的颁发者CA
    对比,用于校验证书是否为合法机构办法
  • 如果找不到,浏览器就会报错,说明服务器发来的证书不可信任
  • 如果找到,那么浏览器就会从操作系统中取出颁发者CA的公钥,然后对服务器发来的证书里的签名
    进行解密
  • 浏览器使用相同的hash算法计算出服务器发来的证书的hash值,将这个计算的hash值与证书中的
    签名对比
  • 对比结果一直,则证明服务器发来的证书合法,没有被冒充。浏览器就可以读取证书中的公钥,用
    于后续加密

延伸:https加密过程
浏览器在解析证书后得到公钥
浏览器生成一个随机值,用公钥加密,发送给服务器
服务器得到这个随机值后,用私钥解密,得到用于信息对称加密的密钥
服务器对信息进行对称加密,发送给浏览器
浏览器得到加密的信息后,用之前的随机值,也就是密钥进行对称解密得到信息。

HTTP 存在的问题

HTTP 没有密码加密,无法保证通信内容不被窃听,攻击者可以截取客户发送的数据并得到他的信息。

HTTP 没有报文完整性验证,无法确保通信内容在传输过程中不被改变,攻击者可以篡改客户通信内容。

HTTP 没有身份鉴别,无法让通信双方确认对方的身份,攻击者可以伪装成客户或者服务器。

加密原理

HTTPS 即 HTTP over SSL,在 HTTP 传输上增加了 SSL 安全性服务。SSL 是安全套接字层,通过采用机密性、数据完整性、服务器鉴别以及客户鉴别来强化 TCP,主要用于为发生在 HTTP 之上的事务提供安全性。SSL 会对数据进行加密并把加密数据送往 TCP 套接字,在接收方,SSL 读取 TCP 套接字中的数据并解密,然后把数据交给应用层。HTTPS 采用混合加密机制,使用非对称加密传输对称密钥来保证传输过程的安全性,之后使用对称加密进行通信来保证通信过程的效率。

HTTPS 的传输过程主要分为两部分:通过 SSL 握手建立安全的 HTTPS 通道和在安全的通道上进行数据传输,SSL 握手的步骤如下:

① 客户发送它支持的密码算法列表,以及一个客户的不重数,不重数就是在一个协议的生存期只使用一次的数。

② 服务器从该列表中选择一种对称加密算法(例如 AES),一种公钥加密算法(例如 RSA)和一种报文鉴别码算法。服务器把它的选择以及证书和一个服务器不重数返回给客户。

③ 客户通过 CA 提供的公钥验证该证书,验证成功后提取服务器的公钥,生产一个前主密钥 PMS,用服务器的公钥加密该 PMS,并将加密的 PMS 发送给服务器。

④ 客户和服务器独立地从 PMS 和不重数中计算出仅用于当前 SSL 会话的主密钥 MS,然后该 MS 被切片以生成两个密码和两个报文鉴别码密钥。自从以后,客户和服务器之间发送的所有报文均被加密和鉴别(使用报文鉴别码)。

⑤ 客户和服务器分别发送所有握手报文的一个报文鉴别码。这一步是为了使握手免受篡改危害,在第一步中客户提供的算法列表是以明文形式发送的,因此可能被攻击者截获并删除较强的算法。当客户发送一个级联它以及发送和接收的所有握手报文的报文鉴别码,服务器能够比较这个报文鉴别码和它已经接受和发送的握手报文的报文鉴别码,如果不一致就终止连接。类似的,客户也可以通过服务器发送的报文鉴别码来检查一致性。

第一步和第二步中的不重复数用于防止重放攻击,每个 TCP 会话使用不同的不重复数就可以使加密密钥不同,当收到重放的 SSL 记录时,该记录无法通过完整性检查,假冒的电子事务不会成功。

当结束 SSL 会话时,需要在类型字段中指出该记录是否是用于终止 SSL 会话的。通过包含这样一个字段,如果客户或服务器在收到一个关闭 SSL 记录之前突然收到了一个 TCP FIN,就知道遭受了截断攻击。

HTTP与HTTPS之间的区别,HTTPS链接建立的过程,了解对称加密算法和非对称加密算法不?

HTTP与HTTPS之间的区别:

HTTP HTTPS
默认端口80 HTTPS默认使用端口443
明文传输、数据未加密、安全性差 传输过程ssl加密、安全性较好
响应速度快、消耗资源少 响应速度较慢、消耗资源多、需要用到CA证书

HTTPS链接建立的过程:

1.首先客户端先给服务器发送一个请求

2.服务器发送一个SSL证书给客户端,内容包括:证书的发布机构、有效期、所有者、签名以及公钥

3.客户端对发来的公钥进行真伪校验,校验为真则使用公钥对对称加密算法以及对称密钥进行加密

4.服务器端使用私钥进行解密并使用对称密钥加密确认信息发送给客户端

5.随后客户端和服务端就使用对称密钥进行信息传输

对称加密算法

双方持有相同的密钥,且加密速度快,典型对称加密算法:DES、AES

非对称加密算法

密钥成对出现(私钥、公钥),私钥只有自己知道,不在网络中传输;而公钥可以公开。相比对称加密速度较慢,典型的非对称加密算法有:RSA、DSA

HTTP请求有哪些。get和Post区别。

HTTP请求:

方法 描述
GET 向特定资源发送请求,查询数据,并返回实体
POST 向指定资源提交数据进行处理请求,可能会导致新的资源建立、已有资源修改
PUT 向服务器上传新的内容
HEAD 类似GET请求,返回的响应中没有具体的内容,用于获取报头
DELETE 请求服务器删除指定标识的资源
OPTIONS 可以用来向服务器发送请求来测试服务器的功能性
TRACE 回显服务器收到的请求,用于测试或诊断
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器

get和Post区别:

GET POST
可见性 数据在URL中对所有人可见 数据不会显示在URL中
安全性 与post相比,get的安全性较差,因为所 发送的数据是URL的一部分 安全,因为参数不会被保存在浏览器 历史或web服务器日志中
数据长度 受限制,最长2kb 无限制
编码类型 application/x-www-form-urlencoded multipart/form-data
缓存 能被缓存 不能被缓存

HTTP常见响应状态码,从1xx到5xx

100:Continue — 继续。客户端应继续其请求。

200:OK — 请求成功。一般用于GET与POST请求。

301:Moved Permanently — 永久重定向。

302:Found — 暂时重定向。

400:Bad Request — 客户端请求的语法错误,服务器无法理解。

403:Forbideen — 服务器理解请求客户端的请求,但是拒绝执行此请求。

404:Not Found — 服务器无法根据客户端的请求找到资源(网页)。

500:Internal Server Error — 服务器内部错误,无法完成请求。

502:Bad Gateway — 作为网关或者代理服务器尝试执行请求时,从远程服务器接收到了无效的响应。

重定向和转发区别

转发是服务器行为,重定向是客户端行为。

转发(Forword) 通过 RequestDispatcher 对象的forward(HttpServletRequest request,HttpServletResponse response)方法实现的。RequestDispatcher 可以通过HttpServletRequestgetRequestDispatcher()方法获得。例如下面的代码就是跳转到 login_success.jsp 页面。

1
request.getRequestDispatcher("login_success.jsp").forward(request, response);

重定向(Redirect) 是利用服务器返回的状态码来实现的。客户端浏览器请求服务器的时候,服务器会返回一个状态码。服务器通过 HttpServletRequestResponse 的 setStatus(int status)方法设置状态码。如果服务器返回 301 或者 302,则浏览器会到新的网址重新请求该资源。

  1. 从地址栏显示来说:forward 是服务器请求资源,服务器直接访问目标地址的 URL,把那个 URL 的响应内容读取过来,然后把这些内容再发给浏览器。浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址。redirect 是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址。所以地址栏显示的是新的 URL。
  2. 转发是服务器行为,重定向是客户端行为;
  3. 转发是浏览器只做了一次访问请求。重定向是浏览器做了至少两次的访问请求;

条件请求

ETag是URL的tag,用来标示URL对象是否改变。这样可以应用于客户端的缓存:服务器产生ETag,并在HTTP响应头中将其传送到客户端,服务器用它来判断页面是否被修改过

一、If-Match

服务端有个ETag(实体标记)的字段,与特定资源关联的确定值,当资源更新后Etag也会随之更新。

所以当客户端If-Match的值若与服务端的ETag一致,才会执行请求,否则会拒绝412

img

二、If-Modified-Since

If-Modified-Since会告知服务器若If-Modifed-Since字段值早于资源的更新时间,则希望服务端能处理该请求;

若If-Modifed-Since字段值晚于资源的更新时间,则返回状态码304 Not Modified的响应

作用:用于确定代理或客户端拥有的本地资源的有效性。

img

三、If-None-Match

与If-Match相反

四、If-Range

它告知服务器若指定的If-Range字段值和请求资源的ETag值一致时,则作为范围请求处理,否则返回全部资源

(这样做也是合理的,因为ETag不变,说明资源未变,则直接返回客户端请求的资源即可;若资源改变,请求的部分资源没有了,应该返回所有的新资源)

img

若不用If-Range,则需要发两次请求。因为若资源改变,会返回客户端412;客户端再发起请求,获得新资源

网络安全

网络安全主要探讨的问题是攻击者如何攻击计算机网络,以及如何防御这些攻击,或者如何事先预防这样的攻击。

进程和线程

进程

多道程序环境下允许多个程序并发执行,进程就是为了更好地描述和控制程序的并发执行,实现操作系统的并发性和共享性。

进程就是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。系统资源指的是处理机、存储器和其他设备服务于某个进程的时间,例如把处理机资源理解为处理机的时间片才是准确的。因为进程是这些资源分配和调度的独立单位,这就决定了进程一定是一个动态的、过程性的概念。

结构

①进程控制块PCB:进程实体的一部分,进程存在的唯一标识,包括进程描述信息、控制和管理信息、资源分配清单和处理机相关信息。

②程序段:就被进程调度程序调度到CPU执行的程序代码段。

③数据段:进程对应的程序加工处理的原始数据,也可以是程序执行时产生的中间或最终结果。

特征

①动态性 进程是一次程序的执行,具有一定的生命周期,是动态地产生、变化和消亡的。动态性是进程最基本的特征。

②并发性 指多个进程同时存在于内存中,能在一段时间内同时运行。并发性是进程的重要特征,也是操作系统的重要特征。进入进程的目的就是为了使程序能与其他进程的程序并发执行,提高资源利用率。

③独立性 指进程实体是一个能独立运行、独立获得自由和独立接受调度的基本单位。

④异步性 由于进程的相互制约,会使进程具有执行的间断性,即进程按各自独立的,不可预知的速度向前推进。

⑤结构性 每个进程都配置有一个进程控制块PCB对其进行描述,从结构上看进程实体是由程序段、数据段和PCB组成的。

进程的状态和转换

①运行态 进程正在处理机上运行

②就绪态 进程已处于准备运行的状态,获得了除处理机外的一切资源

③阻塞态 进程正在等待某一事件而暂停运行,如等待某资源可用或等待输入/输出流

④创建态 进程正在被创建,尚未转到就绪态

⑤结束态 进程正从系统中消失,可能是正常结束或其他原因中断退出

就绪->运行:处于就绪状态的进程被调度后,获得处理机资源(分派处理机时间片)

运行->就绪:处于运行态的进程在时间片用完后,不得不让出处理机。在可剥夺的操作系统中,当有更高优先级的进程就绪时,调度程序将正在执行的进程转为就绪态,让更高优先级的进程执行。

运行->阻塞:进程请求某一资源的使用和分配或等待某事件的发生(如IO完成),进程以系统调用的形式请求操作系统提供服务。

阻塞->就绪:进程等待的事件到来时,如IO结束或中断结束时,中断处理程序必须把相应进程的状态由阻塞转为就绪态。

进程控制

进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态转换等功能。

进程创建

允许一个进程创建另一个进程,创建者为父进程,被创建者为子进程。子进程可以继承父进程所拥有的资源,当子进程被撤销时,应将父进程的资源归还。撤销父进程时,必须同时撤销所有子进程。

①为新进程分配一个唯一的进程标识号,并申请一个空白PCB。②为进程分配资源,为新进程的程序和数据分配必要内存空间。若资源不足不会创建失败而是进入阻塞态。③初始化PCB,包括标志信息,处理机状态信息,进程优先级等。④若进程就绪队列未满,就将新进程插入就绪队列等待被调度。

进程终止

正常结束,表示进程任务已经完成并准备退出运行。异常结束,表示进程在运行时发生了某种异常,使程序无法继续运行,例如非法指令,IO故障等。外界干预,指进程因为外界请求而终止,例如操作系统干预或父进程请求终止等。

①根据被终止进程的标识符,检索PCB,读出该进程的状态。②若处于执行状态,终止执行,将处理机资源分配给其他进程。③若进程还有子进程,应将所有子进程终止。④将该进程的全部资源归还给父进程或操作系统。⑤将PCB从所在队列删除。

进程阻塞

①找到将要被阻塞进程的PCB。②如果为运行态,保护现场转为阻塞态,停止运行。③把PCB插入相应事件的等待队列。

进程唤醒

①在该事件的等待队列中找到进程对应的PCB。②将其从等待队列中移除,设置状态为就绪态。③将PCB插入就绪队列,等待调度程序调度。

进程切换

①保存处理机上下文,包括程序计数器和其他寄存器。②更新PCB信息。③把进程的PCB移入相应的队列。④选择另一个进程执行并更新其PCB。⑤更新内存管理的数据结构。⑥恢复处理机上下文。

进程通信

①共享存储:在通信的进程之间存在一块可以直接访问的共享空间,共享存储分为两种:低级的共享基于数据结构,高级的共享基于存储区。操作系统只负责为通信进程提供可共享的存储空间和同步互斥工具,数据交换由用户自己安排读写指令完成。

②消息传递:进程间的数据交换以格式化的消息为单位,进程提供系统提供的发送消息和接收消息两个原语进行数据交换。消息传递分为:直接通信方式,把消息挂在接收进程的消息缓存队列上。间接通信方式,发送进程把消息发送到某个中间实体,中间实体一般称作信箱,相应的通信系统为电子邮件系统。

③管道通信:消息传递的一种特殊方式,管道就是连接一个读进程和一个写进程来实现它们通信的一个共享文件。管道可以理解为共享存储的优化和发展,管道通信中存储空间优化为缓冲区,缓冲区只允许一边写入另一边读出,只要缓冲区有数据进程就能从缓冲区读出,只要有数据写进程就不会往缓冲区写数据,因此管道通信是半双工通信。


线程

引入进程的目的是为了多道程序更好的并发执行,提高资源利用率和吞吐量;引入线程的目的是为了减少程序在并发执行时的时空开销,提高操作系统的并发性能。

线程就是一种轻量级的进程,是一个基本的CPU执行单位,也是程序执行流的最小单元,由线程ID、程序计数器、寄存器集合和堆栈组成。线程是进程中的一个实体,是操作系统独立调度和分配的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它与同一进程下的其他线程共享进程的全部资源。

线程和进程的区别

①调度:进程是拥有资源的基本单位,而线程是独立调度的基本单位。在同一进程中,线程的切换不会引起进程的切换。在不同进程中线程的切换会引起进程切换。

②拥有资源:不管是传统操作系统还是有线程的操作系统,进程都是拥有资源的基本单位,而线程不拥有系统资源,只有一点运行中必不可少的资源。如果线程也是拥有资源的单位,那么切换线程就需要较大的时空开销,它的引入就没有意义。

③系统开销:创建和撤销进程涉及资源的分配和回收,操作系统的开销远大于创建或撤销线程的开销。进程切换也需要涉及CPU环境的保存和新调度到进程CPU环境的设置,但线程切换只需要保存和设置少量的寄存器容量,开销很小。

④地址空间:进程的地址空间之间互相独立,同一进程的各个线程共享进程的资源,进程内的线程对其他进程不可见。

⑤通信:进程间通信需要同步和互斥手段的辅助,保证数据一致性。线程可以直接读写进程数据段(全局变量)来进行通信。

线程的实现方式

①用户级线程:有关线程管理的所有工作都由应用程序完成,内核意识不到线程的存在。

②内核级线程:线程管理的所有工作都由内核完成,应用程序没有进行线程管理的代码,只有一个到内核级线程的编程接口。


TCP异常处理?

tcp 异常处理,什么时候有RST?

什么时候有PSH URG 的包

死锁

死锁就是指多个进程因为互相竞争资源而陷入的一种僵局,如果没有外力的作用,这些进程都无法继续向前推进。

死锁的原因包含了:

①不可剥夺资源数量的不足,如果是可剥夺资源是不会造成死锁的。

②进程的推进顺序非法,进程请求和释放资源的顺序不当,例如进程P1和P2分别占用资源R1和R2,而此时P1和P2又分别申请资源R2和R1。

③信号量的使用不当,彼此等待对方的消息。

死锁有四个必要条件:

①互斥条件,进程对资源的占用具有排他性控制,如果进程请求的资源已被占用,请求就会被阻塞。

②不可剥夺条件,当一个资源没有被使用完成前是不能被其他进程强行获取的,只有占用它的进程主动释放才可以。

③请求和保持条件,一个进程已经占有了某个资源,又要请求其他资源,而该资源被其他进程占用,请求被阻塞,但进程也不会释放自己已经占有的资源。

④循环等待条件,存在一个进程资源的循环等待链,链中每个进程已经占有的资源同时是其他进程请求的资源。

预防

事先预防,实现起来比较简单,但是条件严格,效率很低。

①破坏互斥条件,系统中的所有资源都允许共享,但是有的资源不能同时访问,不太现实。

②破坏不可剥夺条件,允许剥夺其他进程已经占有的资源,可能会造成前段工作的失效,如果频繁发送就会增加系统开销,严重降低系统的吞吐量。

③破坏请求和保持条件,采用预先资源分配法,一次性分配进程需要的所有资源,缺点是会严重浪费系统资源。

④破坏循环等待条件,采用顺序资源分配法, 缺点是会造成编程不便。

避免

同样也是事先预防,不同的是动态地根据情况来避免死锁,性能比较好。

①系统安全状态,不安全的系统可能会导致死锁,安全的系统状态不会导致死锁,如果资源分配不会进入不安全的系统状态就给进程分配资源。

②银行家算法,把操作系统视为银行家,操作系统管理的资源视为资金,进程向操作系统申请资源相当于贷款。采用预先资源分配策略,主要的数据结构是可利用的资源向量,分配矩阵,需求矩阵,最大需求矩阵。

检测

画出资源分配图,圆圈表示进程,框表示一类资源。进程到资源是请求边,资源到进程是分配边。然后利用死锁定理来简化资源分配图,如果S不可被完全简化那么代表是一个死锁。

解除

如果没有采取死锁的预防和避免,就要采用死锁的检测和解除。

①资源剥夺法:挂起某些死锁进程并剥夺其资源。

②撤销进程法:撤销一个甚至全部死锁进程并剥夺其资源。

③进程回退法:让一个或多个进程回到不至于造成死锁的状态。

分页分段

传统存储管理方式:操作系统引入了虚拟内存的概念,利用计算机的空间局部性和时间局部性原理,将程序分的一部分装入内存运行,其余部分留在外存,等需要的时候再讲外存的程序装入内存继续运行。

虚拟内存实现方式:

请求分页,请求分段,请求段页式存储管理。请求分页存储管理中,将虚拟地址内存空间划分为大小相等的页块,同时内存地址空间,也划分为等大小的页块。系统维持一个页表,存储这虚拟页号到物理快块号的映射。程序中的逻辑地址由两部分组成:页号P和页内位移量W。块号*块大小加上页内偏移得到物理地址。

如果程序执行时,调用到不再内存中的虚拟页面时,发生缺页中断,将页由外存调入内存。如果内存已满,采用页面置换算法将老的淘汰,载入新的。页面置换算法常见的有FIFO,LRU。

image-20201024091740786

优点:没有外碎片,每个内碎片不超过页的大小。

缺点:程序全部装入内存,要求有相应的硬件支持,如地址变换机构缺页中断的产生和选择淘汰页面等都要求有相应的硬件支持。增加了机器成本和系统开销。

请求分段存储管理:

将用户程序地址空间分成若干个大小不等的段,每段能够定义一组相对完整的逻辑信息。存储分配时,以段为单位,段内地址连续,段间不连续。虚拟地址由段号和段内地址组成,虚拟地址到实存地址的变换通过段表来实现。 分页对程序猿而言是不可见的。而分段通常对程序猿而言是可见的,因而分段为组织程序和数据提供了方便。段页式存储组织是分段式和分页式结合的存储组织方法。这样可充分利用分段管理和分页管理的长处。

image-20201024091751743

优点:可以分别编写和编译,可以针对不同类型的段采取不同的保护,可以按段为单位来进行共享,包括通过动态链接进行代码共享。

缺点:会产生碎片。

段页式

程序的地址空间划分成多个拥有独立地址空间的段,每个段上的地址空间划分成大小相同的页。这样既拥有分段系统

的共享和保护,又拥有分页系统的虚拟内存功能。

image-20201024091706330

大内核和微内核有什么区别?

  • 大内核,就是将操作系统的全部功能都放进内核里面,组成一个紧密连接整体。大内核的优点就是效率高,但是很难定位bug,拓展性比较差,每次需要增加新的功能,都要将新的代码和原来的内核代码重新编译。
  • 微内核与单体内核不同,微内核只是将操作中最核心的功能加入内核,包括IPC、地址空间分配和基本的调度,这些东西都在内核态运行,其他功能作为模块被内核调用,并且是在用户空间运行。微内核比较好维护和拓展,但是效率可能不高,因为需要频繁地在内核态和用户态之间切换。

Socket

作者:风雨下钟山
链接:https://www.nowcoder.com/discuss/468422
来源:牛客网

Socket通信流程是怎样的?

图片说明

  • 概括地说,就是通信的两端都建立了一个 Socket ,然后通过 Socket 对数据进行传输。通常服务器处于一个无限循环,等待客户端的连接。
  • 对于客户端,它的的过程比较简单,首先创建 Socket,通过TCP连接服务器,将 Socket 与远程主机的某个进程连接,然后就发送数据,或者读取响应数据,直到数据交换完毕,关闭连接,结束 TCP 对话。
  • 对于服务端,先初始化 Socket,建立流式套接字,与本机地址及端口进行绑定,然后通知 TCP,准备好接收连接,调用 accept() 阻塞,等待来自客户端的连接。如果这时客户端与服务器建立了连接,客户端发送数据请求,服务器接收请求并处理请求,然后把响应数据发送给客户端客户端读取数据,直到数据交换完毕。最后关闭连接,交互结束。

延伸问题:从TCP连接的角度说说Socket通信流程。

图片说明

首先是三次握手的Socket交互流程。

  1. 服务器调用 socket()bind()listen() 完成初始化后,调用 accept() 阻塞等待;
  2. 客户端 Socket 对象调用 connect() 向服务器发送了一个 SYN 并阻塞;
  3. 服务器完成了第一次握手,即发送 SYNACK 应答;
  4. 客户端收到服务端发送的应答之后,从 connect() 返回,再发送一个 ACK 给服务器;
  5. 服务器 Socket 对象接收客户端第三次握手 ACK 确认,此时服务端从 accept() 返回,建立连接。

接下来就是两个端的连接对象互相收发数据。

图片说明

然后是四次挥手的Socket交互流程。

  1. 某个应用进程调用 close() 主动关闭,发送一个 FIN
  2. 另一端接收到 FIN 后被动执行关闭,并发送 ACK 确认;
  3. 之后被动执行关闭的应用进程调用 close() 关闭 Socket,并也发送一个 FIN
  4. 接收到这个 FIN 的一端向另一端 ACK 确认。

close_wait产生原因

通常,CLOSE_WAIT 状态在服务器停留时间很短,如果你发现大量的 CLOSE_WAIT 状态,那么就意味着被动关闭的一方没有及时发出 FIN 包,一般有如下几种可能:

  • 程序问题:如果代码层面忘记了 close 相应的 socket 连接,那么自然不会发出 FIN 包,从而导致 CLOSE_WAIT 累积;或者代码不严谨,出现死循环之类的问题,导致即便后面写了 close 也永远执行不到。
  • 响应太慢或者超时设置过小:如果连接双方不和谐,一方不耐烦直接 timeout,另一方却还在忙于耗时逻辑,就会导致 close 被延后。响应太慢是首要问题,不过换个角度看,也可能是 timeout 设置过小。
  • BACKLOG 太大:此处的 backlog 不是 syn backlog,而是 accept 的 backlog,如果 backlog 太大的话,设想突然遭遇大访问量的话,即便响应速度不慢,也可能出现来不及消费的情况,导致多余的请求还在队列里就被对方关闭了。

如果你通过「netstat -ant」或者「ss -ant」命令发现了很多 CLOSE_WAIT 连接,请注意结果中的「Recv-Q」和「Local Address」字段,通常「Recv-Q」会不为空,它表示应用还没来得及接收数据,而「Local Address」表示哪个地址和端口有问题,我们可以通过「lsof -i:」来确认端口对应运行的是什么程序以及它的进程号是多少。

如果是我们自己写的一些程序,比如用 HttpClient 自定义的蜘蛛,那么八九不离十是程序问题,如果是一些使用广泛的程序,比如 Tomcat 之类的,那么更可能是响应速度太慢或者 timeout 设置太小或者 BACKLOG 设置过大导致的故障。

第二次挥手和第三次挥手能不能合并

第二次挥手的目的是确认你刚才给我发的包已经收到了,第三次挥手的目标是一个新的请求,因为第一次挥手数据包过来时服务器要有两件事要做,diyijianercihuishoudehuifu第一件二次挥手的回复,第二件通过应用程序解阻塞之后才能调用close,这个应用程序有可能调用了close,也有可能没调用,只要不调用close,就没有第三次挥手,如果第一次挥手发了数据包之后,服务器是要尽快去认,应用程序里面迟迟不调用close,所以第三次挥手迟迟发不了,如果把二和三合并一起,第三次迟迟发不了,两次挥手都发不了,客户端还等着呢,所以不能合并,拆开发。

那为什么会有close_wait状态呢

·在服务器与客户端通信的过程中,因为服务器未关闭socket导致closed_wait的发生,当客户端不断地发送连接请求的时候,这样打开的文件描述符就会不断增加。在linux系统中,一个进程可以最大同时打开的文件描述符是有限的。通过ulimit可以查看。

IO复用?

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

1、select、poll和epoll
·select、poll、epoll都可以监听多个文件描述符,等待指定的超时时间,直到一个或者多个文件描述符上有事件发生时返回。返回的值就是文件描述符的数量。返回0表示没有事件发生。

·差别:
(1)事件集
·select有三种类型的描述符类型:readfds、writefds、exceptfds,分别对应读、写、异常条件的描述符集合。因此,select不能处理这三种事件以外的事件类型。并且,每一次select会使得内核直接对fd_set进行修改,再下一次使用select的时候需要重置fd_set。每次select返回的都是注册了的事件集合,包括了就绪和没有就绪的,程序检索就绪事件的时间复杂度为O(n)

·poll对select进行了改进,poll的参数是一个结构体pollfd。poll不会修改描述符,因此每次使用不需要重置pollfd。但是,poll仍然是返回注册了的事件集合,包括了就绪和没有就绪的,程序检索就绪事件的时间复杂度为O(n)。

·epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵
红黑树上,通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理,进程调用 epoll_wait() 便可以得到事
件完成的描述符。使得检索的时间复杂度达到O(1)

(2)支持最大的文件描述符
·select:受到系统的限制,由<sys/select.h>头文件中的FD_SETSIZE宏决定,通常是1024
·poll和epoll一般为65535

(3)工作模式
·select和poll只能工作在相对来说低效的水平触发模式(LT)
·epoll可以工作在高效的边缘触发模式(ET),也可以工作在水平触发模式

(4)实现原理
·select和poll都是基于轮询的方式,每一次的调用都要扫描整个注册的文件描述符集合,并将其中就绪的文件描述符返回给用户,因此检测就绪事件的时间复杂度是O(n)
·epoll_wait是采用回调的方式,内核检测到了就绪文件描述符,就会触发回调函数,回调函数就将该文件描述符上对应的事件插入内核就绪队列中,内核最后在适当的时机将该就绪事件队列中的内容拷贝到用户空间。因此epoll_wait无需轮询检测哪些事件已经就绪,其时间复杂度是O(1)
·epoll需要触发回调函数,因此更适用于连接数目多,但活动连接较少的情况。

同步与异步,阻塞和非阻塞

同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)
所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。
换句话说,就是由调用者主动等待这个调用的结果。

而异步则是相反,调用\在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。

阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.

·阻塞是指结果返回前,当前进程直接被挂起,一直等待结果的到来; 非阻塞则立刻返回,执行后续操作

·同步阻塞:当前进程在等待时,没有执行其他操作而是被挂起
·同步非阻塞:线程等待的时候,执行其它操作(效率低,很有可能设计线程切换的操作)

·异步阻塞:线程在等待消息通知时被挂起
·异步非阻塞:线程不等待,可以去做其他事情

工作模式

epoll 的描述符事件有两种触发模式:LT(level trigger)和 ET(edge trigger)。

  1. LT 模式
    当 epoll_wait() 检测到描述符事件到达时,将此事件通知进程,进程可以不立即处理该事件,下次调用 epoll_wait()
    会再次通知进程。是默认的一种模式,并且同时支持 Blocking 和 No-Blocking。
  2. ET 模式
    和 LT 模式不同的是,通知之后进程必须立即处理事件,下次再调用 epoll_wait() 时不会再得到事件到达的通知。
    很大程度上减少了 epoll 事件被重复触发的次数,因此效率要比 LT 模式高。只支持 No-Blocking,以避免由于一个
    文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。

工作场景

很容易产生一种错觉认为只要用 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 的描述符存储在内核,不容易调试。

arp欺骗

在使用以太网交换机的网络中,攻击者向某个以太网交换机发送大量的伪造源 MAC 地址,以太网交换机收到这样的帧就把虚假的 MAC 源地址填入到交换表中,由于伪造的数量很大很快就填满了表,导致以太网交换机无法正常工作。

1.解决方法:利用交换机防止ARP攻击

在交换机上绑定MAC地址与IP地址,为每台主机添加一条IP地址和MAC地址对应的关系静态地址表。用户发送数据包时,若交换机获得的IP和MAC地址与之前建立的映射表匹配,则发送的包能通过,否则将丢弃该数据包,从而有效地防止ARP欺骗。

2.[DHCP snooping](https://baike.baidu.com/item/DHCP snooping),网上设备可借由DHCP保留网络上各计算机的MAC地址,在伪造的ARP数据包发出时即可侦测到。此方式已在一些厂牌的网上设备产品所支持。

3.每台计算机的ARP一律改用静态的方式,不过这在大型的网上是不可行的,因为需要经常更新每台计算机的ARP表。

SYN flood

Syn-Flood攻击是当前网络上最为常见的DDoS攻击,也是最为经典的拒绝服务攻击,它利用了TCP协议实现上的一个缺陷,通过向网络服务所在端口发送大量的伪造源地址的攻击报文,就可能造成目标服务器中的半开连接队列被占满,从而阻止其他合法用户进行访问。

解决方法

1.无效连接监视释放

这种方法不停监视系统的半开连接和不活动连接,当达到一定阈值时拆除这些连接,从而释放系统资源。

2.延缓TCB分配方法

从前面SYN Flood原理可以看到,消耗服务器资源主要是因为当SYN数据报文一到达,系统立即分配TCB,从而占用了资源。而SYN Flood由于很难建立起正常连接,因此,当正常连接建立起来后再分配TCB则可以有效地减轻服务器资源的消耗。常见的方法是使用SYN Cache和SYN Cookie技术。

SYN Cache技术:

这种技术是在收到SYN数据报文时不急于去分配TCB,而是先回应一个SYN ACK报文,并在一个专用HASH表(Cache)中保存这种半开连接信息,直到收到正确的回应ACK报文再分配TCB。

SYN Cookie技术:

对于SYN攻击,SYN Cache虽然不分配TCB,但是为了判断后续对方发来的ACK报文中的Sequence Number的正确性,还是需要使用一些空间去保存己方生成的Sequence Number等信息,也造成了一些资源的浪费。Syn Cookie技术则完全不使用任何存储资源,这种方法比较巧妙,它使用一种特殊的算法生成Sequence Number,这种算法考虑到了对方的IP、端口、己方IP、端口的固定信息,以及对方无法知道而己方比较固定的一些信息,如MSS、时间等,在收到对方的ACK报文后,重新计算一遍,看其是否与对方回应报文中的(SequenceNumber-1)相同,从而决定是否分配TCB资源。

3.使用SYN Proxy防火墙

SYN Cache技术和SYN Cookie技术总的来说是一种主机保护技术,需要系统的TCP/IP协议栈的支持,而目前并非所有的操作系统支持这些技术。因此很多防火墙中都提供一种 SYN代理的功能,其主要原理是对试图穿越的SYN请求进行验证后才放行,下图描述了这种过程:

DNS欺骗?

DNS欺骗就是攻击者冒充域名服务器的一种欺骗行为。 原理:如果可以冒充域名服务器,然后把查询的IP地址设为攻击者的IP地址,这样的话,用户上网就只能看到攻击者的主页,而不是用户想要取得的网站的主页了,这就是DNS欺骗的基本原理。

  1. 进行IP地址和MAC地址的绑定

    (1)预防ARP欺骗攻击。因为DNS攻击的欺骗行为要以ARP欺骗作为开端,所以如果能有效防范或避免ARP欺骗,也就使得DNS ID欺骗攻击无从下手。例如可以通过将Gateway Router 的Ip Address和MAC Address静态绑定在一起,就可以防范ARP攻击欺骗。

2.直接使用IP地址访问

对个别信息安全等级要求十分严格的WEB站点尽量不要使用DNS进行解析。由于DNS欺骗攻击中不少是针对窃取客户的私密数据而来的,而多数用户访问的站点并不涉及这些隐私信息,因此当访问具有严格保密信息的站点时,可以直接使用IP地址而无需通过DNS解析,这样所有的DNS欺骗攻击可能造成的危害就可以避免了。除此,应该做好DNS Server的安全配置项目和升级DNS软件,合理限定DNS Server进行响应的IP地址区间,关闭DNS Server的递归查询项目等。

3.对DNS数据包进行监测

在DNS欺骗攻击中,Client会接收到至少两个DNS的数据响应包,一个是真实的数据包,另一个是攻击数据包。欺骗攻击数据包为了抢在真实应答包之前回复给Client,它的信息数据结构与真实的数据包相比十分简单,只有应答域,而不包括授权域和附加域。因此,可以通过监测DNS响应包,遵循相应的原则和模型算法对这两种响应包进行分辨,从而避免虚假数据包的攻击。