TCP协议

tcp:称为传输控制协议。

tcp协议的格式

确认应答机制

tcp为每个字节都进行了编号,即为序列号

每一个ack都带有确认序列号,意思告诉发送者下个数据从哪个序号开始发送

 超时重传机制

1.主机A向主机B发送的数据包,由于网络拥堵等原因没有到达主机B,这时主机A会重新发送数据包。

产生丢包有两种情况:第一种主机A向主机B发送的数据包丢失。第二种主机B向主机A发送的ack确认应答包丢失。

超时时间如何确定?

linux中超时以500ms进行控制,每次盘判定超时的时间都是500ms的整数倍,如果重发一次之后仍然得不到应答,下一次等待2*500ms进行冲重传,超时

时间是以指数形式递增的,累计到达一定的超超时次数认为主机端出现异常,就会强制关闭连接。 

连接管理机制

在正常的情况下,tcp要经历三次握手四次挥手断开连接。

 

三次握手具体流程:

第一次握手主机A向主机B发送syn请求建立A到B的连接,此时主机A的状态为syn_sent.

第二次握手主机B向主机A回复ack+syn,此时的ack回复的是第一次握手,syn请求建立B到A的连接,此时主机B的状态为syn_rcvd. 

第三次握手主机A向主机B回复第二次握手的syn,主机A的状态为established,主机B的状态置为established。

四次挥手的具体流程:

第一次挥手:主机A向主机B发送fin请求关闭A到B的连接。

第二次挥手:主机B回复ack给主机A,此时主机B的状态为close_wait。

第三次挥手:主机B发送fin请求关闭B到A的连接。

第四次挥手:主机A回复ack,此时主机A的状态置为time_wait,主机B收到后状态置为closed,主机A在等待2msl后状态置为closed。

第二三步为啥不能合并?

第二步是tcp在系统内核实现时,自动回应的ack,第三步是应用程序手动调用socke.close来关闭。

主机a的状态为什么是time_wait而不是closed?

主机A在回复第四次挥手ack时,可能会产生丢包,因此到达超时时间后主机B会重新第三个数据报,要求主机A再次回复ack.

一般而言服务器大量出现closed_wait可能的原因是服务端没有正确关闭socket,导致四次挥手没有完成。因此只需要调用closed进行关闭即可

 滑动窗口

想一下为什么会出现这个机制,究其原因是因为客户端一发一收的模式性能比较第,为了提高传输效率所以引出了滑动窗口的概念,指一次性可以发送多条数据

窗口的大小指的是无需等待确认应答可以继续发送数据的最大值。当收到第一个ack时滑动窗口向后移动一个窗口。

操作系统为了维护窗口大小保证数据无误传输,需要开辟接受缓冲区来记录当前还有那些数据没有应答,只有确认应答的数据才可以从缓冲区中删掉。

可能产生的丢包问题?

1.数据包已经抵达,ack丢了,这种情况下部分ack丢了,可以通过后续的ack来进行确认。

2.发送的数据包直接丢了,服务端会一直重复发送丢失的数据包的ack,直至重发后,接受端会根据接收缓冲区发送最后一个确认序号的ack

 流量控制

接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应.因此TCP支持根据接收端的处理能力, 来决定发送端的发送速度. 这个机制就叫做流量控制.

接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 "窗口大小" 字段, 通过ACK端通知发送端;窗口大小字段越大, 说明网络的吞吐量越高;
接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端;发送端接受到这个窗口之后, 就会减慢自己的发送速度;
如果接收端缓冲区满了, 就会将窗口置为0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端
 

拥塞控制

虽然TCP有了滑动窗口这个大杀器, 能够高效可靠的发送大量的数据. 但是如果在刚开始阶段就发送大量的数据, 仍然可能引发问题.
因为网络上有很多的计算机, 可能当前的网络状态就已经比较拥堵. 在不清楚当前网络状态下, 贸然发送大量的数据, 是很有可能引起雪上加霜的.
TCP引入 慢启动 机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据
 

 延迟应答

如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小
假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K;
但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;
在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;
如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M;

捎带应答

在延迟应答的基础上, 我们发现, 很多情况下, 客户端服务器在应用层也是 "一发一收" 的. 意味着客户端给服务器说了
"How are you", 服务器也会给客户端回一个 "Fine, thank you";那么这个时候ACK就可以搭顺风车, 和服务器回应的 "Fine, thank you" 一起回给客户端
 

 粘包问题

首先要明确, 粘包问题中的 "包" , 是指的应用层的数据包.

在TCP的协议头中, 没有如同UDP一样的 "报文长度" 这样的字段, 但是有一个序号这样的字段.
站在传输层的角度, TCP是一个一个报文过来的. 按照序号排好序放在缓冲区中.
站在应用层的角度, 看到的只是一串连续的字节数据.
那么应用程序看到了这么一连串的字节数据, 就不知道从哪个部分开始到哪个部分, 是一个完整的应用层数据包

如何避免粘包问题呢? 归根结底就是一句话, 明确两个包之间的边界
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值