TCP协议

未匹配的标注

传输层

端口对端口(实际就是进程对进程)

这一层的协议包括TCP协议,UDP协议

tcp/ip体系中,传输层端口好使用16bit标识,65535个。

端口号
熟知端口:0~1023,一些重要的协议使用的端口,例如http 80, DNS 53, ftp 21/20
登记端口:1024~49151,必须按照IANA规定的手续登记,防止重复
短暂端口:49152~65535, 留给客户端暂时使用的,当服务器收到报文时,就知道了客户端进程使用了动态端口号,通信结束后,这个端口后可以供其他客户进程使用。
DNS请求

本地未查找到域名的ip缓存,会向DNS服务器发送请求

TCP协议
流量控制-修改滑动窗口大小

发送方发送几个数据报后,接收方会回复一个ACK报文:

ACK=1:表示这是一个确认报文
ack=200: 确认的字节序号是200
rwnd=300: 告诉发送方当前的发送窗口调整为300(接收方根据自己的滑动窗口剩余来设置的)

发送方收到确认报文后,修改发送窗口大小为300,并且移动发送窗口到201位置,如果窗口还有剩余,就继续发送数据报。

拥塞控制-调整拥塞窗口,发送几个报文,才返回ack确认报文

发送方每次发送一个数据报文,接收方回复一个ACK报文,在网络好时,会影响传输效率。发送方维护一个拥塞窗口cwnd,表示连续发送几个报文(连续发送的时间间隔很短,可以看成是同时发送)才等待ack报文确认。相当于1个RTT时间,发送的报文数量。

拥塞控制就是调整拥塞窗口的大小,大小从1开始,每进行一个RTT,就调整一下拥塞窗口大小。

调整的算法有:慢开始(指数增加),拥塞避免(每次加1),快重传,快恢复。

超时重传-根据ack报文判断是否漏包

RTT: 发送方发送报文(可能是n个报文),接收方返回一个ack报文,这个过程所用的时间。

tcp可靠传输的实现

发送窗口[21,…..50]

接收方窗口[0,…..30], ack包会通知发送方当前收到最大的连续的字节序+1,比如ACK报文中,ack=31,则表明0-30的字节都收到,如果只接收了[0…30,32..35],由于漏了31,最大的连续字节序任然是30,所以ACK报文任然是ack=31,表明想接收字节序号为31的数据(快重传就是根据ack的值来判断是否要重传字节序的)

tcp连接建立

连接的作用:

1.确认双方都存在

2.协商一些传输参数(例如最大窗口值)

img

半连接队列

服务端接收到客户端的SYN报文后,也会发送SYN,并且 ACK 客户端的 SYN,进入SYN_RCVD状态,服务器会把此种状态下请求连接放到一个半连接队列中。

syn攻击:发送大量的syn连接请求,接收到服务端syn+ack后却不回复,导致服务端的半连接队列爆满

可以开启tcp_syncookies,简单说SYNcookie就是将连接信息编码在ISN(initialsequencenumber)中返回给客户端,这时server不需要将半连接保存在队列中,而是利用客户端随后发来的ACK带回的ISN还原连接信息,以完成连接的建立,避免了半连接队列被攻击SYN包填满
全连接队列(Accept队列)

服务端进入Established状态后,会把连接从半连接队列移动到全连接队列中。
Accept()函数就是读取全连接队列,如果队列为空,会阻塞等待。如果Accept()函数处理太慢,就可能造成全队列溢出。

全队列大小控制
Linux内核参数 /proc/sys/net/core/somaxconn指定,默认值是128。超出数量的TCP连接会直接丢弃或者返回reset报文。丢弃的TCP连接数可以使用netstat -s查看。客户端异常中可以看到很多 connection reset by peer 的错误,那 么就可以证明是由于服务端 TCP 全连接队列溢出的问题

# netstat -s |grep overflowed
    74351 times the listen queue of a socket overflowe  #累计的数字

对于某个应用程序,还会通过backlog控制tcp连接数量。比如nginx的配置

server {
     listen       80 backlog=1000;
     server_name  localhost;

查看当前全队列大小ss -lnt

[root@izwz97ww79qca7m2kxb6hqz ~]# ss -lnt
State       Recv-Q Send-Q Local Address:Port               Peer Address:Port             
LISTEN      0      128     *:80                  *:*                              
LISTEN      0      128     *:443  

# Recv-Q表示已经accept的连接
# Send-Q表示全队列大小
为啥是三次握手

其实就是问第三次握手,发送方最后一次握手返回ack来确认。

三次握⼿才可以阻⽌复历史连接的初始化(主要原因)

服务端返回ack=x+1,客户端需要验证一下这个x是否是第一次握手发送的x,正确无误就发送ack给服务端握手成功,如果错误,就发送reset报文告诉接收方,取消前两次的握手。

三次握⼿才可以同步双⽅的初始序列号

三次握⼿才可以避免资源浪费

tcp连接释放

TCP协议

为啥发起方最后要等待2MSL才断开?

防止最后一个ACK确认报文没有到达服务端,服务端会重新发送FIN=1,ACK=1的报文到这个连接,而客户端已经处于关闭状态,可能会用另外一个进程也配置了这个连接(客户端端口用完后会重新分配),造成了新的客户端连接出问题。

所有2MSL可以让当前的连接报文从网络中消失后,客户端才处于关闭状态,端口才能重新分配给其他进程使用。

只有主动断开的一方需要Time_wait

比如linux服务主动断开连接,time_wait时间为60s.

保活计时器

如果TCP服务器会为每个连接维护一个计时器,防止客户端很久(2h)都没发送消息,判断一下客户端是否还活着。

TCP报文

序号:占32bit,表示当前报文的数据载荷第一个字节的序号

确认号:32bit, 希望收到的下一个字节序号,也就是当前收到的序号+1,报文的ACK=1时这个值才有效。

数据偏移:表示报文首部长度

校验和:校验数据

TCP协议

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 查看所有版本


暂无话题~