TCP是一种面向连接的,可靠的数据传输:确认和重传机制,

    一、客户端和服务器端所经历的状态
    结合连接和释放过程图看状态转换图,以下是客户端的状态转换图:
    TCP的面向连接可靠传输 - 图1

    服务器端的状态转换图:
    TCP的面向连接可靠传输 - 图2

    完整的状态转换图(红线是客户端的过程,蓝线是服务器的过程,表示正常的连接和断开过程):
    TCP的面向连接可靠传输 - 图3
    断开过程中的状态解析

    (1) FIN_WAIT_1: FIN_WAIT_1 和 FIN_WAIT_2 状态的真正含义都是表示等待对方的 FIN 报文。而这两种状态的区别是: FIN_WAIT_1 状态实际上是当 socket 在ESTABLISHED状态时,它想主动关闭连接,向对方发送了 FIN 报文,此时该 socket 即进入到 FIN_WAIT_1 状态。而当对方回应 ACK 报文后,则进入到 FIN_WAIT_2 状态。当然在实际的正常情况下, FIN_WAIT_1 状态一般是比较难见到的(这个过程比较快),而 FIN_WAIT_2 状态还有时常常可以用 netstat 看到(因为有一方还在发数据)。(主动关闭连接)

    (2) FIN_WAIT_2:上面已经详细解释了这种状态,实际上 FIN_WAIT_2 状态下的 socket 表示半连接,即有一方要求 close 连接,但另外一方告诉对方,我暂时还有点数据需要传送给你(发送 ACK 报文),稍后再关闭连接。(主动关闭连接)

    (3) TIME_WAIT:表示收到了对方的 FIN 报文,并发送出了 ACK 报文,就等 2MSL 后即可回到 CLOSED 可用状态了。如果 FIN_WAIT_1 状态下,收到了对方同时带 FIN 标志和 ACK 标志的报文时(被动方没有数据发送),可以直接进入到 TIME_WAIT 状态,而无须经过 FIN_WAIT_2 状态。(主动关闭连接)

    (4) CLOSING(比较少见): 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送 FIN 报文后,按理来说是应该先收到(或同时收到)对方的 ACK 报文,再收到对方的 FIN 报文。但是 CLOSING 状态表示你发送 FIN 报文后,并没有收到对方的 ACK 报文,反而却也收到了对方的 FIN 报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时关闭一个 socket 的话,那么就出现了双方同时发送 FIN 报文的情况,也即会出现 CLOSING 状态,表示双方都正在关闭 socket 连接。

    (5) CLOSE_WAIT: 被动方需要查看是否还有数据发送给对方,如果没有的话,那么你也就可以关闭这个 socket,发送 FIN 报文给对方,即关闭连接。所以在 CLOSE_WAIT 状态下,需要完成的事情是等待被动方去关闭连接。(被动方)

    (6) LAST_ACK: 它是被动关闭的一方在发送 FIN 报文后,最后等待对方的 ACK 报文。当收到 ACK 报文后,也即可以进入到 CLOSED 可用状态了。(被动方)

    (7) CLOSED: 表示连接中断。

    二、TCP 协议如何保证可靠传输
    TCP的任务是在IP层的不可靠、尽力而为服务的基础上建立一种可靠数据传输服务。TCP提供的可靠数据传输服务就是要保证接收方进程从缓冲区读出的字节流与发送方发出的字节流是完全一样的。TCP使用了校验、序号、确认和重传机制来达到这个目的。

    TCP,控制传输协议,和UDP的差别很大,它充分实现了数据传输时的各种控制功能:
    针对发送端发出的数据包的确认应答信号ACK
    针对数据包丢失或者出现定时器超时的重发机制
    针对数据包到达接收端主机顺序乱掉的顺序控制
    针对高效传输数据包的流动窗口控制
    针对避免网络拥堵时候的流量控制
    针对刚开始启动的时候避免一下子发送大量数据包而导致网络瘫痪的慢启动算法和拥塞控制。
    而这些在UDP中都是没有的!此外,TCP作为一种面向有连接的控制传输协议,只有在确认对端主机存在时才会发送数据,从而可以控制通信流量的浪费。
    TCP通过序列号、检验和、确认应答信号、重发控制、连接管理、窗口控制、流量控制、拥塞控制实现可靠性。

    应用数据被分割成 TCP 认为最适合发送的数据块。
    TCP 给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。
    校验和: TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
    TCP 的接收端会丢弃重复的数据。
    流量控制: TCP 连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。 (TCP 利用滑动窗口实现流量控制)
    拥塞控制: 当网络拥塞时,减少数据的发送。
    停止等待协议: 也是为了实现可靠传输的,它的基本原理就是每发完一个分组就- 停止发送,等待对方确认。在收到确认后再发下一个分组。 超时重传: 当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段

    三、校验
    校验

    在计算校验和时,要在TCP数据报之前增加12个字节的伪首部,伪首部并不是TCP报文段真正的首部。只是在计算校验和时,临时添加在TCP数据报文段的前面,得到一个临时的TCP报文段。伪首部既不向下传送也不向上递交,而仅仅是为了计算校验和。注意:IP数据报的校验和只检验IP数据报的首部,但TCP的校验和会把首部和数据部分一起检验。

    序号

    TCP首部的序号字段用来保证数据能有序提交给应用层,TCP把数据看成一个无结构但是有序的字节流,而序号是建立在传送的字节流之上,而不是建立在报文段之上。TCP连接中传送的数据流中的每一个字节都编上一个序号。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。

    确认

    TCP首部的确认号是期望收到对方的下一个报文段的数据的第一个字节的序号。TCP默认使用累计确认,即TCP只确认数据流中至第一个丢失字节为止的字节。例如,接收方B收到了发送方A发送的包含字节0~2和6~7的报文段。由于某些原因,B还没有收到字节3~5的报文段,此时B仍在等待字节3(和其后面的字节),因此,B到A的下一个报文段将确认号字段设置为3。

    重传

    有两种事件会导致TCP对报文段进行重传:超时和冗余ACK。

    (1) 超时

    TCP每发送一个报文段,就对这个报文段设置一次计时器。只要计时器设置的重传时间到期但还没有收到确认,就要重传这一报文段。当检测到接收数据有错误时,会采取直接丢弃出错的数据,发送端等待接收端的确认超时后,会自动重发该报文段。

    由于IP数据报在传输的时候选择的路由变化很大,因此传输层的往返时延的方差很大。为了计算超时计时器的重传时间,TCP采用一种自适应算法,它记录一个报文段发出的时间,以及收到相应确认的时间,这两个时间之差叫做报文段的往返时间(RTT)。TCP保留了RTT的一个加权平均往返时间RTTs,当第一次测量RTT样本时,RTTs值就为所测量到的RTT样本的值,但之后每测量一个新的RTT样本,就按下式重新计算一次RTTs:

    新的RTTs = ( 1- a ) * (旧的RTTs) + a(新的RTT样本)

    在上式中0 <= a < 1。若a很接近于零,表示新的RTTs值和旧的RTTs值相比变化不大,而受新的RTT样本影响不大(RTT值更新较慢)。若a接近于1,则表示新的RTTs值受新的RTT样本的影响较大(RTT值更新较快)。[RFC 2988]推荐的a值为0.125。

    所以超时计时器设置的超时重传时间(RTO)应略大于上面得出的加权平均往返时间RTTs。即RTO = RTTs + 4RTTd。其中RTTd是RTT的偏差的加权平均值,它与RTTs和新的RTT样本之差有关。当第一次测量时,RTTd取为测量到的RTT样本值的一半,以后测量中,使用下式计算:新的RTTd = (1-β) (旧的RTTd) + β|RTTs - 新的RTT样本|,其中β是个小于1的系数,它的推荐值是0.25。

    (2) 冗余ACK

    超时触发重传存在的一个问题就是超时周期往往太长。幸运的是,发送方通常可在超时事件发生之前通过注意冗余ACK来较好地检测丢包情况。冗余ACK就是再次确认某个报文段的ACK,而发送方先前已经收到过该报文段的确认。例如,发送方A发送了序号为1、2、3、4、5的TCP报文段,其中2号报文段丢失了,它将无法到达接收方B。因此,3、4、5号报文段对于B来说就成了失序报文段。TCP规定每当比期望序号大的失序报文段到达时,发送冗余ACK,指明下一个期望字节的序号[RFC 1122, RFC 2581]。在这个例子中,3、4、5号报文到达B,但它们不是B所期待的下一个报文,于是B就发送3个对1号报文段的冗余ACK,表示自己期望接收2号报文段。TCP规定当发送方收到对同一个报文段的3个冗余ACK时,就可以认为跟在这个被确认报文段之后的报文段已经丢失。就前面的例子而言,当A收到对于1号报文段的3个冗余ACK时,则它可以认为2号报文段已经丢失。这时发送方A可以立即对2号报文执行重传,这种技术成为快速重传