计算机网络体系结构
OSI七层模型
OSI采用了分层的结构化技术,共分七层,物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
TCP/IP模型
OSI模型比较复杂且学术化,所以我们实际使用的TCP/IP模型,共分4层,链路层、网络层、传输层、应用层。两个模型之间的对应关系如图所示:
无论什么模型,每一个抽象层建立在低一层提供的服务上,并且为高一层提供服务。
TCP/IP协议族
Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,是 Internet 最基本的协议、Internet 国际互联网络的基础,由网络层的 IP 协议和传输层的 TCP 协议组成。协议采用了4层的层级结构。然而在很多情况下,它是利用 IP 进行通信时所必须用到的协议群的统称。
TCP/IP 网络传输中的数据
每个分层中,都会对所发送的数据附加一个首部,在这个首部中包含了该层必要的信息,如发送的目标地址以及协议相关信息。通常,为协议提供的信息为包首部,所要发送的内容为数据。在下一层的角度看,从上一层收到的包全部都被认为是本层的数据。
网络中传输的数据包由两部分组成:一部分是协议所要用到的首部,另一部分是上一层传过来的数据。首部的结构由协议的具体规范详细定义。在数据包的首部,明确标明了协议应该如何读取数据。反过来说,看到首部,也就能够了解该协议必要的信息以及所要处理的数据。
① 应用程序处理
首先应用程序会进行编码处理,这些编码相当于 OSI 的表示层功能;
编码转化后,邮件不一定马上被发送出去,这种何时建立通信连接何时发送数据的管理功能,相当于 OSI 的会话层功能。
② TCP 模块的处理
TCP 根据应用的指示,负责建立连接、发送数据以及断开连接。TCP 提供将应用层发来的数据顺利发送至对端的可靠传输。为了实现这一功能,需要在应用层数据的前端附加一个 TCP 首部。
③ IP 模块的处理
IP 将 TCP 传过来的 TCP 首部和 TCP 数据合起来当做自己的数据,并在 TCP 首部的前端加上自己的 IP 首部。IP 包生成后,参考路由控制表决定接受此 IP 包的路由或主机。
④ 网络接口(以太网驱动)的处理
从 IP 传过来的 IP 包对于以太网来说就是数据。给这些数据附加上以太网首部并进行发送处理,生成的以太网数据包将通过物理层传输给接收端。
⑤ 网络接口(以太网驱动)的处理
主机收到以太网包后,首先从以太网包首部找到 MAC 地址判断是否为发送给自己的包,若不是则丢弃数据。
如果是发送给自己的包,则从以太网包首部中的类型确定数据类型,再传给相应的模块,如 IP、ARP 等。这里的例子则是 IP 。
⑥ IP 模块的处理
IP 模块接收到数据后也做类似的处理。从包首部中判断此 IP 地址是否与自己的 IP 地址匹配,如果匹配则根据首部的协议类型将数据发送给对应的模块,如 TCP、UDP。这里的例子则是 TCP。
另外吗,对于有路由器的情况,接收端地址往往不是自己的地址,此时,需要借助路由控制表,在调查应该送往的主机或路由器之后再进行转发数据。
⑦ TCP 模块的处理
在 TCP 模块中,首先会计算一下校验和,判断数据是否被破坏。然后检查是否在按照序号接收数据。最后检查端口号,确定具体的应用程序。数据被完整地接收以后,会传给由端口号识别的应用程序。
⑧ 应用程序的处理
接收端应用程序会直接接收发送端发送的数据。通过解析数据,展示相应的内容。
TCP 和 UDP
网际协议IP是TCP/IP中非常重要的协议。负责对数据加上IP地址(有发送它的主机的地址(源地址)和接收它的主机的地址(目的地址))和其他的数据以确定传输的目标。
而 TCP 和 UDP 都是传输层的协议,传输层主要为两台主机上的应用程序提供端到端的通信。
但是 TCP 和 UDP 最不同的地方是,TCP 提供了一种可靠的数据传输服务,TCP 是面向连接的,也就是说,利用 TCP 通信的两台主机首先要经历一个建立连接的过程,等到连接建立后才开始传输数据,而且传输过程中采用“带重传的肯定确认”技术来实现传输的可靠性。TCP 还采用一种称为“滑动窗口”的方式进行流量控制,发送完成后还会关闭连接。所以 TCP 要比 UDP 可靠的多。
UDP(User Datagram Protocol的简称, 中文名是用户数据报协议)是把数据直接发出去,而不管对方是不是在接收,也不管对方是否能接收的了,也不需要接收方确认,属于不可靠的传输,可能会出现丢包现象,实际应用中要求程序员编程验证。
注意:
我们一些常见的网络应用基本上都是基于 TCP 和 UDP 的,这两个协议又会使用网络层的 IP 协议。但是我们完全可以绕过传输层的 TCP 和 UDP,直接使用 IP,比如 Linux 中 LVS,甚至直接访问链路层,比如 tcpdump 程序就是直接和链路层进行通信的。
上图中,其他一些协议的名称解释:
ICMP 控制报文协议
IGMP internet组管理协议
ARP 地址解析协议
RARP 反向地址转化协议
详解 TCP 协议特点
TCP 是传输层协议,对应 OSI 网络模型的第四层传输层,特点如下。
- TCP 协议是基于链接的,也就是传输数据前需要先建立好链接,然后再进行传输。
- TCP 链接一旦建立,就可以在链接上进行双向的通信。
- TCP 的传输是基于字节流而不是报文,将数据按字节大小进行编号,接收端通过 ACK 来确认收到的数据编号,通过这种机制,TCP 协议能够保证接收数据的有序性和完整性,因此 TCP 能够提供可靠性传输。
- TCP 还能提供流量控制能力,通过滑动窗口来控制数据的发送速率。滑动窗口的本质是动态缓冲区,接收端根据自己的处理能力,在 TCP 的 Header 中动态调整窗口大小,通过 ACK 应答包通知给发送端,发送端根据窗口大小调整发送的的速度。
- 仅仅有了流量控制能力还不够,TCP 协议还考虑到了网络问题可能会导致大量重传,进而导致网络情况进一步恶化,因此 TCP 协议还提供拥塞控制。TCP 处理拥塞控制主要用到了慢启动、拥塞避免、拥塞发生、快速恢复四个算法。
序列号,确认号
- 序列号seq(Sequence Numbers):用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记
- 确认序号ACK(Acknowledge Number):在接收端,用来通知发送端数据成功接收;其数值等于发送方的发送序号+1(即接收方期望接收的下一个序列号);
- 标志位:
(A)SYN:创建一个连接
(B)ACK:确认序号有效
(C)FIN:终结一个连接
(D)RST:重置连接。
(E)PSH:接收方应该尽快将这个报文交给应用层。
(F)URG:紧急指针(urgent pointer)有效。
TCP三次握手
TCP 是基于链接的,所以在传输数据前需要先建立链接,TCP 在传输上是双工传输,不区分 Client 端与 Server 端,为了便于理解,我们把主动发起建连请求的一端称作 Client 端,把被动建立链接的一端称作 Server 端。
如下图,建连的时序是从上到下,左右两边分别代表 Client 端与 Server 端当时的链接状态。
TCP 提供面向有连接的通信传输。面向有连接是指在数据通信开始之前先做好两端之间的准备工作。
所谓三次握手是指建立一个 TCP 连接时需要客户端和服务器端总共发送三个包以确认连接的建立。在 socket 编程中,这一过程由客户端执行 connect 来触发。
第一次握手:客户端将标志位 SYN 置为1,随机产生一个值 seq=J,并将该数据包发送给服务器端,客户端进入 SYN_SENT 状态,等待服务器端确认。
第二次握手:服务器端收到数据包后由标志位 SYN=1 知道客户端请求建立连接,服务器端将标志位 SYN 和 ACK 都置为1,ack=J+1,随机产生一个值 seq=K,并将该数据包发送给客户端以确认连接请求,服务器端进入 SYN_RCVD 状态。
第三次握手:客户端收到确认后,检查 ack 是否为J+1,ACK 是否为1,如果正确则将标志位 ACK 置为1,ack=K+1,并将该数据包发送给服务器端,服务器端检查 ack 是否为K+1,ACK 是否为1,如果正确则连接建立成功,客户端和服务器端进入 ESTABLISHED 状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。
为什么 TCP 握手需要三次?
TCP 是可靠的传输控制协议,而三次握手是保证数据可靠传输又能提高传输效率的最小次数。
原因:
为了实现可靠数据传输, TCP 协议的通信双方,都必须维护一个序列号, 以标识发送出去的数据包中,哪些是已经被对方收到的。
例如:发送方在发送数据包(假设大小为 10 byte)时, 同时送上一个序号( 假设为 500),那么接收方收到这个数据包以后, 就可以回复一个确认号(510 = 500 + 10) 告诉发送方 “我已经收到了你的数据包, 你可以发送下一个数据包, 序号从 511 开始” 。
三次握手的过程即是通信双方相互告知序列号起始值,并确认对方已经收到了序列号起始值的必经步骤。
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。
至于为什么不是四次,很明显,三次握手后,通信的双方都已经知道了对方序列号起始值,也确认了对方知道自己序列号起始值,第四次握手已经毫无必要了。
TCP 的三次握手的漏洞-SYN洪泛攻击
TCP 三次握手中是有一个缺陷的,就是如果我们利用三次握手的缺陷进行攻击。这个攻击就是 SYN 洪泛攻击。三次握手中有一个第二次握手,服务端向客户端应答请求,应答请求是需要客户端 IP 的,攻击者就伪造这个 IP,往服务器端狂发送第一次握手的内容,当然第一次握手中的客户端 IP 地址是伪造的,从而服务端忙于进行第二次握手但是第二次握手当然没有结果,所以导致服务器端被拖累,死机。
面对这种攻击,有以下的解决方案,最好的方案是防火墙。
无效连接监视释放
这种方法不停监视所有的连接,包括三次握手的,还有握手一次的,反正是所有的,当达到一定(与)阈值时拆除这些连接,从而释放系统资源。这种方法对于所有的连接一视同仁,不管是正常的还是攻击的,所以这种方式不推荐。
延缓TCB分配方法
一般的做完第一次握手之后,服务器就需要为该请求分配一个 TCB(连接控制资源),通常这个资源需要200多个字节。延迟 TCB 的分配,当正常连接建立起来后再分配 TCB 则可以有效地减轻服务器资源的消耗。
使用防火墙
防火墙在确认了连接的有效性后,才向内部的服务器(Listener)发起SYN请求
详解四次挥手断连
TCP 的断连,如下图所示。
TCP 链接的关闭,通信双方都可以先发起,我们暂且把先发起的一方看作 Client,从图中看出,通信中 Client 和 Server 两端的链接都是 ESTABLISHED 状态,然后 Client 先主动发起了关闭链接请求,Client 向 Server 发送了一个 FIN 包,表示 Client 端已经没有数据要发送了,然后 Client 进入了 FIN_WAIT_1 状态。
Server 端收到 FIN 后,返回 ACK,然后进入 CLOSE_WAIT 状态。此时 Server 属于半关闭状态,因为此时 Client 向 Server 方向已经不会发送数据了,可是 Server 向 Client 端可能还有数据要发送。
当 Server 端数据发送完毕后,Server 端会向 Client 端发送 FIN,表示 Server 端也没有数据要发送了,此时 Server 进入 LAST_ACK 状态,就等待 Client 的应答就可以关闭链接了。
Client 端收到 Server 端的 FIN 后,回复 ACK,然后进入 TIME_WAIT 状态。TIME_WAIT 状态下需要等待 2 倍的最大报文段生存时间,来保证链接的可靠关闭,之后才会进入 CLOSED 关闭状态。而 Server 端收到 ACK 后直接就进入 CLOSED 状态。
为什么需要等待 2 倍最大报文段生存时间之后再关闭链接,原因有两个:
- 保证 TCP 协议的全双工连接能够可靠关闭;
- 保证这次连接的重复数据段从网络中消失,防止端口被重用时可能产生数据混淆。
从这个交互流程可以看出,无论是建连还是断链,都是需要在两个方向上进行,只不过建连时,Server 端的 SYN 和 ACK 合并为一次发送,而断链时,两个方向上数据发送停止的时间可能不同,所以不能合并发送 FIN 和 ACK。这就是建连三次握手而断链需要四次的原因。
另外回答断链的问题时,可以提到实际应用中有可能遇到大量 Socket 处在 TIME_WAIT 或者 CLOSE_WAIT 状态的问题。一般开启 tcp_tw_reuse 和 tcp_tw_recycle 能够加快 TIME-WAIT 的 Sockets 回收;而大量 CLOSE_WAIT 可能是被动关闭的一方存在代码 bug,没有正确关闭链接导致的。
-
为什么要等待 2MSL
客户端发送的第4次握手报文,服务器没有收到。这时候服务器端会再次发送一个 FIN =1 的报文,而这个时候客户端还处于 TIME_WAIT 状态,所以可以再次发送确认消息。
如果有大量的连接,每次在连接、关闭时都要经历三次握手、四次挥手,这很显然会造成性能低下。因此,HTTP 有一种叫作 keepalive connections 的机制,它可以在传输数据后仍然保持连接,当客户端需要再次获取数据时,直接使用刚刚空闲下来的连接而无须再次握手。
为什么需要三次握手,两次确认?
为什么客户端还要发送一次确认呢,主要是为了防止已失效的链接请求报文突然又传到了服务器端,造成错误。比如:客户端发送链接请求,因为网络或者一些其它因素造成没有在一定时间到达服务器端,所以客户没有收到确认。由于客户端会重发一次链接请求,通过三次握手与服务器建立连接,但是这时上次的请求到达服务器端了,服务器会误以为客户端又发了一次新的链接请求,会向客户端发送报文同意建立连接,但是客户端已经建立连接了,就会放弃该报文,服务端没有收到响应,也就不会建立连接了。-
三次握手出现错误时的应对措施?
第一次握手A发送SYN传输失败,A,B都不会申请资源,连接失败。如果一段时间内发出多个SYN连接请求,那么A只会接受它最后发送的那个SYN的SYN+ACK回应,忽略其他回应全部回应,B中多申请的资源也会释放第二次握手B发送SYN+ACK传输失败,A不会申请资源,B申请了资源,但收不到A的ACK,过一段时间释放资源。如果是收到了多个A的SYN请求,B都会回复SYN+ACK,但A只会承认其中它最早发送的那个SYN的回应,并回复最后一次握手的ACK
第三次握手ACK传输失败,B没有收到ACK,释放资源,对于后序的A的传输数据返回RST(重置连接)。实际上B会因为没有收到A的ACK会多次发送SYN+ACK,次数是可以设置的,如果最后还是没有收到A的ACK,则释放资源,对A的数据传输返回RST
TCP的三次握手与四次挥手理解及面试题(很全面)
三次握手与四次挥手面试问题
三次握手和四次挥手
计算机网络:图文解析TCP的三次握手、四次挥手