网络 || TCP协议

什么是tcp协议

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

四层负载均衡:传输层(transmission),tcp和udp。

TCP/IP模型与OSI模型的比较

模型相同点不同点
TCP/IP两者都是以协议栈的概念为基础。 OSI适用于各种协议栈;TCP/IP只适用于TCP/IP网络。
OSI协议栈中的协议彼此相互独立。OSI是先有模型;TCP/IP是先有协议,后有模型。
下层对上层提供服务。层次数量不同。

传输层的作用

IP层提供点到点的连接,传输层提供端到端的连接。

传输层的协议

TCP(Transmission Control Protocol)

  1.     传输控制协议
  2.     可靠的、面向连接的协议
  3.     传输效率低

UDP(User Datagram Protocol)

  1.     用户数据报协议
  2.     不可靠的、无连接的服务
  3.     传输效率高

通过不同的端口号来区别

不同的应用程序监听不同的端口。

nginx:80

mysql:3306

ssh:22

dns:53

端口号范围:0-65535。

TCP的封装格式

16位源端口号:告知主机该报文段是来自哪里。

16位目标端口号:告知主机该报文段是去往哪里。

32位序列号:一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。

32位确认号:对另一方发送来的TCP报文段的响应。其值是收到的TCP报文段的序列号值加1。

4位首部长度(header length):标识该TCP头部有多少个32bit字(4字节)。因为4位最大能标识15,所以TCP头部最长是60字节。

6个标志位

标志位意义
URG   urgent 紧急
ACKacknowledgement  确认
PSHpush  通知应用程序尽快处理数据,不要让数据在缓存里停留。
RSTreset  重置,重新连接
SYNsync  同步,建立连接
FINfinish  请求断开连接

16位窗口大小(window size):是TCP流量控制的一个手段。这里说的窗口,指的是接收通告窗口(Receiver Window,RWND)。它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。

16位校验和(TCP check sum):由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。

16位紧急指针(urgent pointer):是一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。

三次握手

第一次握手:Host A 给Host B 发一个 SYN 报文,此时HostA处于 SYN_SEND 状态。

第二次握手:Host B 收到Host A 的 SYN 报文之后,会以自己的 SYN 报文作为应答,同时会把Host A的 ISN + 1 作为ACK 的值,表示自己已经收到了Host A 的 SYN,此时Host B 处于 SYN_REVD 的状态。

第三次握手:Host A 收到 SYN 报文之后,会发送一个 ACK 报文,把Host B 的 ISN + 1 作为 ACK 的值,表示已经收到了Host B 的 SYN 报文,此时Host A 处于 ESTABLISHED 状态。Host B 收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。

四次挥手


第一次挥手:Host A 发送一个 FIN 报文,报文中会指定一个序列号。此时Host A 处于 FIN_WAIT1 状态。

第二次挥手:Host B 收到 FIN 之后,会发送 ACK 报文,且把Host A 的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到Host A 的报文了,此时Host B处于 CLOSE_WAIT 状态。

第三次挥手:如果Host B也想断开连接了,和Host A 的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时Host B处于 LAST_ACK 的状态。

第四次挥手:Host A 收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把Host B的序列号值 +1 作为自己 ACK 报文的序列号值,此时Host A 处于 TIME_WAIT 状态。需要过一阵子以确保Host B收到自己的 ACK 报文之后才会进入 CLOSED 状态,Host B收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。

32位序列号

32位的序号:单调递增

A 向 B 发送第一个包 生成初始序号,随机第一个包30给字节,发送第二个包 ISN + 第二个包的第一个字节偏移量,序列号:ISN + 30。ISN = M + Md5(四元组)

序列号随机的。为了安全性,黑客不会那么容易猜到序列号,不会伪造一些确认序列包,从而对服务器发起攻击。

序列号回绕,序列号32位保存,总会到尽头,到达尽头,序列号从0开始:

  •     使用序列号无法判断出那个是以前的包,那个是之后的包。
  •     在选项里加上 timestamp     时间戳  发送方的时间戳 接收方的时间戳。
  •     选项:timestamp -- 计算往返时间,确认数据包的先后顺序。

ack包携带序列号,但是一般不占用,下一个包还可以从ack序列号开始,一般来说你的ack都不占用序列号 ,ack报文不携带数据就不占用序列号,不需要回复的包 基本不占用序列号。

什么是 TCP 半连接队列和全连接队列?

在 TCP 三次握手的时候,Linux 内核会维护两个队列,分别是:

  1. 半连接队列, syn queue
  2. 全连接队列, accept    queue

服务端收到客户端发起的 SYN 请求后,内核会把该连接存储到半连接队列,并向客户端响应 SYN+ACK,接着客户端会返回 ACK,服务端收到第三次握手的 ACK 后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到 accept 队列,等待进程调用 accept 函数时把连接取出来。

计时器

体现了tcp的可靠性。

超时重传计时器:ack包迟迟未收到,服务器端检测超时,服务器重新发送数据包 SYN+ACK

    /proc/sys/net/ipv4/tcp_synack_retries

centos系统,默认发送syn+ack包 5次,内核参数修改:永久生效。

    vim    /etc/sysctl.conf
    sysctl -p
    sysctl -a

坚持计时器:防止零窗口死锁。

保活计时器:防止两个TCP之间的连接长时间的空闲。

时间等待计时器:连接终止期间使用的,在发送了最后一个ACK后,不立即关闭连接,而是等待一段时间,保证能接收到重复的FIN数据段。

SYN攻击

SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。

如何检测?

检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击。

netstat -n -p TCP | grep SYN_RECV

防范措施

syn flood:dmesg日志

1.出现这个日志,要么就是由于半连接队列设置小,要么就是遭受到ddos攻击

修改参数:扩大半连接队列

    /proc/sys/net/ipv4/tcp_max_syn_backlog
    net.ipv4.tcp_max_syn_backlog

2.启用

    [root@localhost ipv4]# cat tcp_syncookies
    1

syn backlog 是 TCP 协议栈中的半连接队列长度。

mss:tcp 最大报文长度。传输层一次最大可以传输多少数据,不包括头部字段。

1500 - ip头(20字节)tcp头部字(最少20)==1460

因为有了MSS tcp包一般来说在网络层是不需要分片的。

netstat 命令用于显示网络状态,可以得知 Linux 系统的网络情况。

[root@localhost ~]# netstat -anplut
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1744/sshd           
tcp        0     36 192.168.102.129:22      192.168.102.1:64105     ESTABLISHED 10694/sshd: root [p 

选项

-a all
-n number 以数字的形式显示
-p program 程序的名字
-l listening
-t tcp
-u udp

状态(state)

sent 发送
received 接受
establish 建立连接

 Recv-Q
       Established: The count of bytes not copied by the user program connected to this socket. 
       内核空间里的socket队列里还有多少数据没有被用户空间里的进程复制(取)走
       说明应用程序非常忙,处理不过来了
       Listening: Since Kernel 2.6.18 this column contains the current syn backlog.

   Send-Q
       Established: The count of bytes not acknowledged by the remote host. 
       还有多少字节的数据没有被远程主机确认--》发送出去的数据包还没有收到确认
       Listening: Since Kernel 2.6.18 this column contains the maximum size of the syn backlog.

socket 套接字: ip:port  192.168.0.1:80 ,一个程序占用一个ip地址的一个端口号,访问这个套接字就是访问一个程序。

流量控制

TCP协议通过滑动窗口来进行流量控制,它是控制发送方的发送速度从而使接受者来得及接收并处理。

阻塞控制

拥塞控制作用于整体网络,它是防止过多的包被发送到网络中,避免出现网络负载过大,网络拥塞的情况。

拥塞控制状态机的状态有五种

1、Open状态

Open状态是拥塞控制状态机的默认状态。这种状态下,当ACK到达时,发送方根据拥塞窗口cwnd(Congestion Window)是小于还是大于慢启动阈值ssthresh(slow start threshold),来按照慢启动或者拥塞避免算法来调整拥塞窗口。

2、Disorder状态

当发送方检测到DACK(重复确认)或者SACK(选择性确认)时,状态机将转变为Disorder状态。在此状态下,发送方遵循飞行(in-flight)包守恒原则,即一个新包只有在一个老包离开网络后才发送,也就是发送方收到老包的ACK后,才会再发送一个新包。

3、CWR状态

发送方接收到一个显示拥塞通知时,并不会立刻减少拥塞窗口cwnd,而是每收到两个ACK就减少一个段,直到窗口的大小减半为止。当cwnd正在减小并且网络中有没有重传包时,这个状态就叫CWR(Congestion Window Reduced,拥塞窗口减少)状态。CWR状态可以转变成Recovery或者Loss状态。

4、Recovery状态

当发送方接收到足够(推荐为三个)的DACK(重复确认)后,进入该状态。在该状态下,拥塞窗口cnwd每收到两个ACK就减少一个段(segment),直到cwnd等于慢启动阈值ssthresh,也就是刚进入Recover状态时cwnd的一半大小。 发送方保持 Recovery 状态直到所有进入 Recovery状态时正在发送的数据段都成功地被确认,然后发送方恢复成Open状态,重传超时有可能中断 Recovery 状态,进入Loss状态。

5、Loss状态

当一个RTO(重传超时时间)到期后,发送方进入Loss状态。所有正在发送的数据标记为丢失,拥塞窗口cwnd设置为一个段(segment),发送方再次以慢启动算法增大拥塞窗口cwnd。

Loss 和 Recovery 状态的区别是:Loss状态下,拥塞窗口在发送方设置为一个段后增大,而 Recovery 状态下,拥塞窗口只能被减小。Loss 状态不能被其他的状态中断,因此,发送方只有在所有 Loss 开始时正在传输的数据都得到成功确认后,才能退到 Open 状态。

拥塞控制主要是四个算法:

1. 慢启动

2. 拥塞避免

3. 拥塞发生(快重传)

4. 快速恢复

为什么需要三次握手,而不是两次?

三次握手才能确立两方都已经准备好了,如果两次握手,客户端没有收到来自服务器端的syn+ack包,而服务端又已经发送了,那服务端认为我发了,客户端认为服务器没有发送,最后一直等着,形成死锁。

等待2MSL的意义?

    1.保证客户端最后发送的ACK能够到达服务器,帮助其正常关闭。

    2.防止已失效的连接请求报文段出现在本连接中。

TIME_WAIT状态过多有什么危害?

1.占用系统资源

2.socket的TIME_WAIT状态结束之前,该socket占用的端口号将一直无法释放。

如何解决TIME_WAIT状态过多?

1,最好的办法是尽量让客户端主动断开连接,除非遇到一些异常情况,如客户端协议错误、客户端超时等。

2,打开系统的TIME_WAIT重用和快速回收。

3,在Linux系统可以修改以下参数:

    ①打开TCP对时间戳的支持,保持服务器与客户端时间同步 

       net.ipv4.tcp_timestamps=1(默认即为 1)

    ②修改net.ipv4.tcp_tw_reuse = 1,允许对处于TIME_WAIT的socket用于建立新的连接

为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

建立连接时,ACK和SYN可以放在一个报文里来发送。而关闭连接时,被动关闭方可能还需要发送一些数据后,再发送FIN报文表示同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

两个存在的理由:

1、无法保证最后发送的ACK报文会一定被对方收到,所以需要重发可能丢失的ACK报文。

2、关闭链接一段时间后可能会在相同的IP地址和端口建立新的连接,为了防止旧连接的重复分组在新连接已经终止后再现。2MSL足以让分组最多存活msl秒被丢弃。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

韩未零

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值