深入理解TCP

  TCP是面向连接的传输层层协议,可以为应用层提供可靠的数据传输服务。所谓的面向连接并不是真正意思上的连接,只不过是在发送数据之前,首先得相互握手,也就是说接收方知道你要发数据给它了。而UDP是面向无连接的传输层协议,并不提供可靠的数据传输。有一个很恰当的比喻:UDP传输就类似于写信,接收方事先并不知道你要写信给他;而TCP传输就像是打电话,必须等对方按了接听键你才能更他通话。

  那么TCP又是如何来实现面向连接和可靠性服务的??在讨论TCP的可靠数据传输之前,我们先看看最简单的传输层服务UDP。

1、UDP

  

  源端口号/目的端口号:同TCP首部中端口号的作用相同

  首部长度:报文段中的字节数(首部加数据)。

  校验和:差错检测,用于确定当UDP报文段从源到达目地移动时,其中的比特是否发生了变化。

  检验和如何计算??

  包括三部分:UDP伪首部、UDP首部、UDP数据部分。伪首部如下所示:

  

  其中,协议字段:TCP为6,UDP为17,UDP长度即为UDP(包括UDP头和数据部分)的总长度。

  • 首先把UDP伪首部添加到UDP的前面,然后把UDP首部中的检验和字段填0,把所有的位划分成16位的字
  • 把所有16位的字相加,如果遇到进位,则将高于16字节的进位部分的值加到最低位上,如:
    • 1011 1011 0101 1110 + 1111 1100 1110 1100 = 1 1011 1000 0100 1010
    • 那么把1 1011 1000 0100 1011最高位的1加到最低位上得1011 1000 0100 1011
  • 将所有字相加得到的结果为一个16位的数,将该数取反即为检验和字段 

  从UDP的首部我们就可以看到,UDP是一个很简陋的传输层协议,只负责从发送端的应用层接收数据,封装层UDP报文段,然后交给下层发送到接收端;在接收端,UDP从下层接收数据,然后送达应用层。在该传输过程中,UDP之提供一个基本的差错检测服务,如果检测没有错误,就直接交给应用层;否则直接丢弃。

  下面我们来看一下TCP提供的可靠传输服务:

2、TCP

  源端口号/目的端口号:用于多路复用/分解来自或送到上层应用的数据。什么意思呢?处于应用层的进程可能有很多,每个进程都有可能通过传输层发送数据到因特网或者通过传输层从因特网中接收数据。那么当传输层从因特网中接收到数据应该发送给应用层中的哪个进程?或者如何知道从应用层收到的数据是属于应用层中的哪个服务??其实这些的实现都是通过端口号的标识的。应用层中的每个网络服务都对应着一个端口号,通过端口号来标识对应的服务。所以说端口号是将传输层绑定到应用层的粘合剂。

  

  序号和确认号:被用来实现可靠数据传输服务。

  接收窗口字段:指示接收方接收缓冲区剩余大小,用于流量控制。

  首部长度字段:TCP首部中有一个选项字段的存在,也就是说TCP首部的长度是可变的,所以需要指明首部的长度。

  选项字段:用于发送方与接收方协商最大报文段长度(MSS)时,或在高速网络环境下用作窗口调节因子时使用。还定义了一个时间戳选项。

  RST、SYN、FIN比特:用于连接的建立和拆除。

  PSH比特:当PSH比特被设置时,表明接收方应该立即将数据交给上层。

  URG比特和紧急数据指针:URG比特指示报文段里存在着被发送端的上层实体置为“紧急”的数据;紧急数据的最后一个字节由16bit的紧急数据指针字段指出。当紧急数据存在并给出紧急数据尾的时候,TCP必须立即通知接收端的上层实体。

  检验和字段:同UDP检验和,提供差错检测。

  TCP 如何保证数据传输的可靠性??

  (1) 在发送数据之前,进行三次握手,保证与接收端相互可靠通信。下面来讲一个三次握手的过程:

  初始状态客户端和服务器都为CLOSED状态,服务器打开listen监听客户连接进入LISTEN状态;然后客户端发送一个SYN包,序列号为j,此时客户端进入SYN_SENT状态;当服务器接收到SYN包时,服务器进入SYN_RECV状态,并且发送一个带SYN的ACK,确认号为j+1,序列号为k;当客户端收到这个带SYN的ACK时,客户端进入ESTABLISHED状态,对于客户端来说,已经确认可以与服务器通信了,所以客户端就可以发数据给服务器了,此时客户端发一个ACK(ACK中可以包含数据信息)到服务器,确认号为k+1;在服务器接收到ACK之前,三次握手还没有完成,虽然客户端可以发数据给服务器,但是只能包含在ACK中,而服务器并不能发数据到客户端,只有当收到ACK后,服务器端进入状态ESTABLISHED状态。自此,三次握手完成,客户端可以与服务器端已经建立了连接,可以互相发送数据。

  一定要进行三次握手么,不能只进行两次或者四次??

  其实这个问题的本质是因特网中信道不可靠, 但是要在这个不可靠的信道上可靠地传输数据,三次握手是最小的理论值。

  如果只进行两次握手,那么当客户端发送一个SYN分组后,会发生两种情况:

  情况一:服务器接收到了这个SYN并返回ACK,无论客户端是否接收到了ACK,服务器都认为已经与客户端建立连接了,于是就开始向客户端发送数据。但是如果客户段没有收到ACK,那么客户端会认为与服务器没有建立连接,就不会接收服务器发来的数据,也就是说直接丢弃服务器发来的数据,服务器发出的消息超时了,就重复发送数据,这就产生了死锁。

  情况二:客户端发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达服务器。本来这是一个早已失效的报文段。但服务器收到此失效的连接请求报文段后,就误认为是客户端再次发出的一个新的连接请求。于是就向客户端发送ACK,但是此时客户端没有发出请求,所以并不会理睬这个ACK,而服务器又开始发数据给客户端了,这时候,客户端又把这些数据都丢弃了,而服务器发出的消息超时了,就重复发送数据,也产生了死锁。

  (2) 通过确认和重传机制来保证数据的完整性和按序交付

  TCP把数据看成是无结构和有序的字节流,所以上面所说的报文段的序列号是该报文段首字节的字节流编号,而报文段中的确认号是主机期望从客户端收到的下一个字节的序号。我们来举个例子:

  假设TCP从应用层接收到3000个字节长度的数据,而TCP最大报文长度MSS为1460,那么就要对数据进行分段,第一段数据为0~1459字节,第二段为1460~2919字节,第三段为2920~2999字节,那么这三个报文段的序列号分别为0、1460、2920。

  假如服务器端接收到客户端发过来的第一个报文段0~1459字节,那么它期望收到的下一个字节的序列号为1460,那么在返回给客户端的ACK中确认号即为1460,然后服务器又收到客户端发来的2920~2999字节的报文,但是未收到1460~2919字节,那么服务器端继续期望下一个接收字节为1460,所以返回的ACK中的确认号依旧为1460。TCP只确认直到第一个未收到字节之前的字节,所以TCP提供的是累积确认接收方保留失序的字节,同时等待缺少的字节来填补间隔。

  当然在如此错综复杂的网络中,即使三次握手建立连接了,也不可能每次发送数据都能成功到达目的地。客户端每次向网络中发送一个报文号,其实还会继续缓存该报文,指导收到服务器端发过来的ACK确认服务器收到了该报文,然后才会丢弃。但是当发送的报文段在网络中发生丢包了或者产生了比特出错又或者服务器返回的ACK丢失了,那么客户端将都收不到ACK。那么怎么办?总不能一直等着吧?

  客户端通过一个定时器超时机制来保证客户端不会无限制地等待。也就是当发送一个报文段后,就启动定时器,当发生超时了还未收到服务器发来的ACK时,客户端就重新发送该报文段。但是设定多长时间呢??从客户端发送一个报文到接收到ACK相当于一个来回,我们用往返时间RTT来表示,设定的这个定时器时间至少得大于RTT吧。如果是ACK丢失了,那么服务器如果收到了这个重发的报文,那么数据不就重复了么??服务器通过序列号来保证数据的无冗余,当服务器收到了这个重复的数据包时,便知道客户端没有收到ACK超时了,就直接把它丢弃,然后返回给客户端一个最新的ACK。

  (3) TCP提供了流量控制和拥塞控制

  流量控制其实是一个速度匹配服务,也就是说发送方发送数据的速率要与接收方应用程序读取速率相匹配,以消除接收端缓冲区溢出的可能性。在TCP首部中有一个字段叫做接收窗口字段,它就是用来通知发送端服务器上剩余的缓冲区的大小(rwnd)的。

  TCP提供的拥塞控制并不是网络辅助的拥塞控制,而是端到端的拥塞控制,因为IP层并不向端系统提供显式的网络拥塞反馈。那么TCP发送方如何限制它的发送速率?发送方又如何知道路径上是否拥塞?

  上面提到当数据包在网络中丢失时就可能发生超时,而服务器段可能收到冗余的数据包,当然客户端也不例外,也可能收到冗余的ACK。所以我们把丢包事件定义为:要么出现超时,要么收到来自接收端的3个冗余的ACK。当丢包事件发生了,客户端就知道链路上存在拥塞。

  发送端维护着一个拥塞窗口(cwnd),一个发送方的缓冲区中未被求确认的数据量不会超过cwnd和rwnd(流量控制中接收窗口字段,服务器上剩余的缓冲区的大小)的最小值。这个约束限制了发送方未被确认的数据量,也就间接限制了发送速率。

  其实TCP是按照如下原则来设置发送速率:

  • 一个丢失的报文段意味着拥塞,因此当丢失报文段时应降低TCP发送方的速率。
  • 一个确认报文段指示该网络正在向接收方交付发送方的报文段,所以,当对先前未确认报文段的确认到达时,能够增加发送方的速率。
  • 因为IP层并不向上层提供显式的网络拥塞反馈,所以TCP是通过ACK和丢包事件来充当隐式信号进行带宽探测。

  那么问题又来了cwnd的值又该如何设置呢??

  通过TCP拥塞控制算法慢启动拥塞避免快速恢复

关于拥塞控制算法具体实现过程说来话长,下一篇博文持续更新,敬请关注博主。

版权所有,欢迎转载,转载请注明出处。

时间: 2025-01-12 01:10:14

深入理解TCP的相关文章

理解TCP和UDP协议

目录 TCP 协议 UDP协议 TCP和UDP的区别 TCP和UDP的使用场景 一 TCP协议 1.TCP的头部格式 理解TCP协议,首要的就是TCP协议的头部格式 ·        Source Port和Destination Port:分别占用16位,表示源端口号和目的端口号:用于区别主机中的不同进程,而IP地址是用来区分不同的主机的,源端口号和目的端口号配合上IP首部中的源IP地址和目的IP地址就能唯一的确定一个TCP连接: ·        Sequence Number:用来标识从T

通过packetdrill构造的包序列理解TCP快速重传机制

TCP的逻辑是极其复杂的,其学习曲线虽然很平缓但其每一步都是异常艰难,好在这些都是体力活,只要肯花时间也就不在话下了.想彻底理解一个TCP的机制,有个四部曲:1.读与其相关的RFC:2.看Linux协议栈的TCP实现:3.通过抓包以及其它工具来确认事实就是如此:4.解决一个与之相关的网络问题.经历了以上四步骤,相信任何人都可以在相关领域内稍微装逼一把了...        本文的内容是TCP快速重传机制,但是与其它文章不同的是,本文并不剖析源码实现,也不翻译RFC,更不是原理性介绍,而是通过一个

理解TCP/IP协议

TCP/IP协议是Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议. 单从TCP/IP协议这个名称看,好多人误以为它是一个协议.其实TCP/IP并不是一个协议,而是一个协议族,这个族里面括很多协议,其中比较主要的是TCP协议和IP协议,所以简称为TCP/IP协议. TCP/IP协议由4层组成,从下到上分别是,网络接口层,网络层,传输层,应用层. 这里有的朋友可能会有疑问,开放系统互联参考模型(OSI)不是有

理解TCP为什么需要进行三次握手(白话)

首先简单介绍一下TCP三次握手     在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接. 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认: 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器 进入SYN_RECV状态: 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此

转_结合Wireshark捕获分组深入理解TCP/IP协议栈

转自: http://blog.chinaunix.net/uid-9112803-id-3212207.html 摘要: 本文剖析了浏览器输入URL到整个页面显示的整个过程,以百度首页为例,结合Wireshark俘获分组进行详细分析整个过程,从而更好地了解TCP/IP协议栈. 一.俘获分组 1.1 准备工作 (1) 清空浏览器缓存 首先清空Web浏览器的高速缓存,确保Web网页是从网络中获取,而不是从高速缓冲取得[1].谷歌浏览器,Options --> Under the Hood -->

理解TCP/IP网络栈&编写网络应用(下)

1.摘要 这是<翻译:理解TCP/IP网络栈&编写网络应用>的下篇,文章中会通过讲解TCP的代码实现帮助大家理解发送.接收数据的流程,也描述了一些网卡.驱动等网络栈底层的原理. 原文地址:原文地址 原作者:Hyeongyeop Kim 2.数据结构 以下是一些关键数据结构.我们了解一下这些数据结构再开始查看代码. 2.1.sk_buff_structure 首先,sk_buff结构或skb结构代表一个数据包.图6展现了sk_buff中的一些结构.随着功能变得更强大,它们也变得更复杂了.

通俗易懂理解TCP和UDP(转)

知乎看到一位大牛"车小胖"的类比很贴切,就转过来了. 原文链接:https://www.zhihu.com/question/51388497 或者:https://daily.zhihu.com/story/9028124 怎么理解 TCP 的面向连接和 UDP 的无连接(不面向连接)? 亚当和夏娃分别生活在两个山头,山头之间是万丈深渊,亚当采集野果需要分享给夏娃,如果他们之间有一条索道(物理连接),野果可以顺着索道滑到夏娃那一边,那就没有车小胖什么事了. 事实上山头之间没有索道,但

wireshark的使用教程--用实践的方式帮助我们理解TCP/IP中的各个协议是如何工作的

 wireshark的使用教程 --用实践的方式帮助我们理解TCP/IP中的各个协议是如何工作的 wireshark是一款抓包软件,比较易用,在平常可以利用它抓包,分析协议或者监控网络,是一个比较好的工具,因为最近在研究这个,所以就写一下教程,方便大家学习. 这里先说Wireshark的启动界面和抓包界面 启动界面: 抓包界面的启动是 按file下的按钮 之后会出现 这个是网卡的显示,因为我有虚拟机所以会显示虚拟网卡,我们现在抓的是真实网卡上的包所以在以太网卡右边点击start 开始抓包 这个就

深入理解TCP、UDP协议及两者的区别

一.TCP协议: 位于传输层, 提供可靠的字节流服务.所谓的字节流服务(Byte Stream Service) 是指, 为了方便传输, 将大块数据分割成以报文段(segment) 为单位的数据包进行管理. 而可靠的传输服务是指, 能够把数据准确可靠地传给对方. 即TCP 协议为了更容易传送大数据才把数据分割, 而且 TCP 协议能够确认数据最终是否送达到对方.所以,TCP连接相当于两根管道(一个用于服务器到客户端,一个用于客户端到服务器),管道里面数据传输是通过字节码传输,传输是有序的,每个字

深入理解TCP协议及其源代码

深入理解TCP协议及其源代码 前言 在前面实验我们分别实现了Socket 通信工具,探讨了Socket API.Socket 调用原理等.但是还没有针对某一实例进行讲解,在本实验我们将针对TCP协议进行详细分析,期待在Linux内核进行分析TCP原理. 1.Tcp基本原理 TCP是一种面向连接.可靠.基于字节流的传输协议,位于TCP/IP模型的传输层. 面向连接:不同于UDP,TCP协议需要通信双方确定彼此已经建立连接后才可以进行数据传输: 可靠:连接建立的双方在进行通信时,TCP保证了不会存在