TCP

TCP首部

  • 20字节

16bit源端口号 16bit目的端口号
32bit序列号
32bit确认序号
4bit首部长度 保留6bit 6bit标识位 16bit窗口大小
16bit校验和 16bit紧急指针

特点

  • 可靠,面向__连接__,字节流,__传输层__的服务(三次握手建立一个连接,四次挥手关闭一个连接)
  • “连接”:客户端和服务器端的内存各自保存关于对方ip,port等信息
  • 使用__校验和__、__确认__和__重传机制__保证__可靠__传输
  • 给数据__分节排序__,使用__累计确认__保证数据的__顺序__和__非重复__
  • 使用__滑动窗口__进行流量控制,通过__动态__改变__窗口大小__进行__拥塞控制__
  • 连接4元组(源IP,源port,目的IP,目的端口)此外,同一个连接应有相同的__协议号__
  • 三个阶段:启动,数据传输,退出(关闭)
  • 双工

TCP字段

  • **ACK ** 确认号用于确认__已成功接受__的N的字节(不包括N),后续ACK可以确认前面丢失ACK的报文
  • **SYN ** 序列号可用于接收端__丢弃重复__的报文段,__记录__以杂乱次序到达的报文段
  • RST 重置连接
  • FIN 结束向对方发送数据

滑动窗口

TCP滑动窗口

TCP可靠传输

加权平均往返时间__RTTs__

\[RTTs=(1-\alpha)*(RTTs)+\alpha*RTT \]

TCP超时时间RTO

\[RTO=RTTs+4*RTT_d \\ _{RTT_d为偏差} \]

流量控制

  • 控制发送方发送速率,保证接收方及时接受
  • 接受方通过发送确认报文中窗口字段控制发送方发送窗口大小。将窗口字段置为0,则发送方不发送数据。

拥塞控制

  • 降低整个网络的拥塞程度

  • 慢开始、拥塞避免、快重传、快恢复
  • 发送方维护__状态变量__拥塞窗口(cwnd)

拥塞控制时拥塞窗口(cwnd)变化

  • 慢开始、拥塞避免

    发送最初慢开始,令cwnd=1,发送方只能发送1个报文段;收到确认后,将cwnd翻倍

    设置慢开始门限(ssthresh), cwnd>=ssthresh时进入拥塞避免每次cwnd加1

    出现超时,ssthresh=cwnd/2

  • 快重传、快恢复

    收到3个重复确认,下一个报文段丢失,执行快重传,立即重传下一个报文段

    只是丢失个别报文段而非网络拥塞,执行快恢复,令ssthresh=cwnd/2,cwnd=sstresh

TCP状态转换图

主动、被动 与 服务器、客户端没有明确的对应关系。

TCP状态转换图

三次握手、四次挥手

三次握手

  1. 第一次握手:客户端发送SYN,并指明客户端的初始序列号,即ISN(c),服务端接受消息,服务端确认的客户端发送能力和服务端的接受能力
  2. 第二次握手:服务端发送ACK+SYN,指明自己的ISN(s)。为了确认客户端的SYN,将ISN(c)+1作为ACK数值。这样,每发送一个SYN,序列号就会加1. 如果有丢失的情况,则会重传。客户端接受,客户端确认客户端接受和发送能力和服务端的接受发送能力
  3. 第三次握手:客户端发送ACK,客户端将ISN(s)+1作为返回的ACK数值,服务端接受,服务端确认服务端的发送能力

四次挥手

  1. 客户端发送一个FIN段,并包含一个希望接收者看到的自己当前的序列号K. 同时还包含一个ACK表示确认对方最近一次发过来的数据。
  2. 服务端将K值加1作为ACK序号值,表明收到了上一个包。这时上层的应用程序会被告知另一端发起了关闭操作,通常这将引起应用程序发起自己的关闭操作。
  3. 服务端发起自己的FIN段,ACK=K+1, seq=L
  4. 客户端确认。ACK=L+1

ISN(Initial Sequence Number)

ISN = M + F(localhost, localport, remotehost, remoteport)

  • M是一个计时器,每隔4微秒加1。
  • F是一个Hash算法,根据源IP、目的IP、源端口、目的端口生成一个随机数值。要保证hash算法不能被外部轻易推算得出。

TIME_WAIT状态

也称2MSL等待状态. 等待两倍于最大段生存期(Maximum Segment Lifetime, MSL)的时间, 加倍等待. 必须为最大段生存期选择一个数值, 代表任何报文段在被丢弃前在网络中被允许存在的最长时间.

  • 保证发送的ACK能到达. 若未成功到达, 则服务器超时重传FIN+ACK报文段, 客户端再重传ACK, 并重新计时
  • 防止已失效的连接请求报文段出现在本连接中, 可使本连接持续时间内所产生的报文段从网络中消失, 使下次连接中不会出现旧的报文段

安全协议与分层

x x
链路层 一跳通信中的信息
网络层 两个主机之间传输的信息
传输层 进程与进程之间的通信
应用层 应用程序操纵的信息

粘包

  • 产生原因
  1. 连续发送数据时,由于使用nagle算法,将较小的内容拼接为较大的内容,一次性发送,造成粘包
  2. 发送较大内容时,接收方读取缓存较小,不能一次读完全部内容,在下次读取内容时读取到上次发送的内容

syn flood

tcp_synack_retries=0 发送第二次握手包之后,如果收不到第三次握手包,不进行重试,加快回收"半连接"

# vi /etc/sysctl.conf

#最关键参数,默认为5,修改为0 表示不要重发
net.ipv4.tcp_synack_retries = 0
#半连接队列长度
net.ipv4.tcp_max_syn_backlog = 200000
#系统允许的文件句柄的最大数目,因为连接需要占用文件句柄
fs.file-max = 819200
#用来应对突发的大并发connect 请求
net.core.somaxconn = 65536
#最大的TCP 数据接收缓冲(字节)
net.core.rmem_max = 1024123000 
#最大的TCP 数据发送缓冲(字节)
net.core.wmem_max = 16777216
#网络设备接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目
net.core.netdev_max_backlog = 165536
#本机主动连接其他机器时的端口分配范围
net.ipv4.ip_local_port_range = 10000 65535

注意,以下参数面对外网时,不要打开。因为副作用很明显,具体原因请google,如果已打开请显式改为0,然后执行sysctl -p关闭。因为经过试验,大量TIME_WAIT状态的连接对系统没太大影响:

#当出现 半连接 队列溢出时向对方发送syncookies,调大 半连接 队列后没必要
net.ipv4.tcp_syncookies = 0
#TIME_WAIT状态的连接重用功能
net.ipv4.tcp_tw_reuse = 0
#时间戳选项,与前面net.ipv4.tcp_tw_reuse参数配合
net.ipv4.tcp_timestamps = 0
#TIME_WAIT状态的连接回收功能
net.ipv4.tcp_tw_recycle = 0

为了处理大量连接,还需改大另一个参数:

# vi /etc/security/limits.conf

在底下添加一行表示允许每个用户都最大可打开409600个文件句柄(包括连接):

  • nofile 409600
posted @ 2019-10-27 10:49  薛定谔的博客  阅读(114)  评论(0编辑  收藏  举报