zoukankan      html  css  js  c++  java
  • 计算机网络 part1 TCP

    一、TCP协议

    references:newcoder
    TCP/IP协议,TCP和UDP的区别及特点

    1、四层模型

    应用层:载有应用程序,将数据发送给传输层。主要协议有HTTP、SMTP、FTP、DNS等。
    传输层:负责应用程序间的通信,将来自应用程序的信息流格式化封装。主要协议有TCP、UDP。
    网络层:将传输层的信息流打包成IP数据包,交给链路层进行不同主机间的通信。主要协议有IP。
    链路层:接收网络层的IP数据包,封装成帧发送到网络;从网络接收物理帧,抽出IP数据包,交给网络层。

    2、可靠性

    1).序列号、校验和、确认应答、超时重传

    每个包都有序列,接收方可以按序号排序;收到数据段,接收方会返回一个相对应的确认字符ACK,ACK一般是我已经收到的序号+1,也就是期望收到下个报文段第一个数据字节的序号;如果发送端在一定时间(这个时间一般是2*RTT(报文段往返时间)+一个偏差值内)未接收到确认应答,那么对应的数据包就会被认为丢失而重传。

    • 校验和:
      1、校验和字段设为0。
      2、把需要校验的数据(TCP首部+TCP数据+TCP伪首部)看成以16位为单位的数字组成,不够的补0。
      3、进行2进制反码求和(最高位进时进位到最低位),存入校验和中。
      4、校验:把需要校验的内容看成16位为单位的数字,进行2进制反码求和,结果为0则正确。

    2).流量控制

    滑动窗口: 是接收方建议发送方的窗口大小,防止发送方一次发送太多数据。
    如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收。
    在滑动窗口内的数据包可以直接发送,当窗口左边发送并且收到确认后窗口就会右移。

    3).拥塞控制

    拥塞窗口: 发送方为了避免出传输路径堵塞所采用的窗口。
    窗口大小的设定:
    慢启动: 一开始将窗口(CWND)设为1,每次收到确认应答(经过一个RTT),拥塞窗口大小*2;当报文段超时重传时,将阈值(ssthresh)设为当前窗口大小的一半,窗口大小设为1,然后慢启动。
    拥塞避免: 设置慢启动阈值, 一般设为65536(2^16)。当拥塞窗口大小到达这个阈值时,不能乘2,而是每次+1;当报文段超时重传时,将阈值设为当前窗口大小的一半,窗口大小设为1,然后慢启动。
    快速重传: 3次收到重复ACK,马上重传。比如三次收到1001确认应答,就说明1001开始没收到,重发1001开始的数据段。
    快速恢复: 收到3个重复ACK,启动快速重传,并且启动快恢复。将阈值设为当前窗口大小的一半,并将拥塞窗口大小设为新的阈值+3(因为收到3个说明之前发出了3个保温,有些不加3)。接下来每收到一次刚才的重复确认,拥塞窗口+1。当收到新的数据确认ACK时,将窗口大小设为慢启动阈值,然后进入拥塞避免。

    3、TCP首部格式(20字节)

    references:理解TCP

    • 源端口号:表示发送端端口号,字段长16位,因为端口号有(2^{16})个。
    • 目标端口号:表示接收端端口号,字段长度16位。
    • 序列号:字段长32位,初始值是个随机值。
    • 确认应答号:下一次应收到的序列号。
    • 数据偏移:可以认为是TCP首部长度,单位是4字节。例如数据库偏移是7,则首部长度为28字节。
    • 窗口大小:字段长16位。
    • 控制位:8位。
    • 校验和:
      1、校验和字段设为0。
      2、把需要校验的数据(TCP首部+TCP数据+TCP伪首部)看成以16位为单位的数字组成,不够的补0。
      3、进行2进制反码求和(最高位进时进位到最低位),存入校验和中。
      4、校验:把需要校验的内容看成16位为单位的数字,进行2进制反码求和,结果为0则正确。

    4、三次握手

    references:TCP的三次握手与四次挥手理解及面试题(很全面)

    基于TCP传输层协议的连接被建立时,发送方和接收方共发送3个包,称为3次握手。
    第一次握手:发送端发送一个SYN=1(同步序列编号)和初始序号Seq=X(随机的)。告诉接收方请求建立连接。客户端进入SYN_SENT状态,请求连接,等待确认。
    第二次握手:接收端确认发送端的SYN(发送ACK=X+1),同时自己也发送一个SYN=1,Seq=Y(随机的)。说明接收端确认收到建立连接信息。服务器进入SYN_RECV状态。
    第三次握手:确认接收方的SYN+ACK包,发送ACK=Y+1,Seq=X+1。此时TCP连接成功。客户端和服务器进入ESTABLISHED状态。

    为什么是三次握手?而不是两次四次?
    防止已经失效的请求连接报文段突然传到服务端,从而产生错误。
    比如,当客户端第一次握手的报文段在网络中因为延迟在某个节点到达服务端,而服务端发出确认应答,同理建立连接。但是客户端此时并没有请求建立连接,那么就会忽视这个确认应答,因为没有第三次握手,那么服务端就会一直等待客户端发送数据。

    5、四次挥手

    第一次挥手:客户端发送释放连接的报文,FIN=1,Seq=u。请求释放连接。客户端进入FIN_WAIT1(终止等待1)状态。
    第二次挥手:服务端收到释放连接的报文,发出确认报文ACK=u+1,并且带上自己的序列号Seq=v。此时,客户端向服务器方向的连接已经断开了,客户端不会继续发送数据。处于半关闭(FIN_WAIT2)状态。但是服务器发送数据,客户端依然要接受。客户端等待服务端的连接释放报文。服务端进入CLOSE_WAIT(关闭等待)状态。客户端收到确认请求后,进入FIN_WAIT2(终止等待2)状态。
    第三次挥手:服务器最后数据发送完毕,向客户端发送释放连接的报文,FIN=1,ACK=u+1,Seq=w。等待客户端确认。服务器进入LAST_ACK(最后确认)状态,等待客户端的确认报文。
    第四次挥手:客户端收到释放连接报文,发出确认,进入TIME_WAIT状态。ACK=w+1,Seq=u+1。服务端收到确认报文立即关闭TCP连接,立即进入CLOSED状态。客户端发送确认报文后,不马上关闭连接,而是等2∗MSL(最长报文段寿命)后关闭。因为最后的确认报文可能丢失,所以要等待,如果服务端没收到确认报文,服务端会超时重传FIN。所以服务端断开TCP连接比客户端早。最后客户端撤销TCP连接,进入CLOSED状态。

    6、同时打开,同时关闭,半打开

    references:TCP-IP详解:TCP半打开连接及同时打开同时关闭
    同时打开:
    两个应用同时主动打开,发送SYN包,进入SYN_SENT状态。他们都收到了对方发送的SYN,然后向对方发送SYN包和ACK包,这时进入SYN_RECV状态。在他们收到对方的SYN和ACK包后,直接建立连接,进入ESTABLISHED状态。

    同时关闭:
    双方同时主动关闭,发送FIN包进入FIN_WAIT1状态。双方收到对方的FIN后进入CLOSING状态,然后发送ACK确认,进入TIME_WAIT状态。最后CLOSED。

    半打开:
    一方因异常关闭(断网、断电),而另一方不知情,这时候就处于半打开连接。如果双方不进行数据通信,仍处于连接状态的一方就不会检测另外一方已经出现异常。如果需要发数据的话,这边收到之后 其实发现这个连接并不存在了,就会回复RST包(reset报文)告知,强制关闭连接,这个时候就需要重新建立连接了。

  • 相关阅读:
    https://www.cnblogs.com/aademeng/category/1042475.html
    python中重要的模块--asyncio 转载
    await这个关键词以及asyncio.wait asyncio.gather
    async get_event_loop
    麦克米伦7000
    [GO]errorr接口的使用
    [GO]断言
    [GO]空接口
    [GO]接口的转换
    [GO]接口的嵌用继承
  • 原文地址:https://www.cnblogs.com/KirinSB/p/12602036.html
Copyright © 2011-2022 走看看