TCP协议(详解)

1 什么是TCP协议?

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

2 TCP协议的通信流程

客户端: 1 创建套接字 ->2为套接字绑定地址信息(客户端不推荐主动绑定)->3向服务端发起连接请求->4发送数据->5接收数据->6关闭套接字

服务端: 1 创建套接字->2为套接字绑定地址信息->3开始监听->4获取已完成连接->5通过获取的已完成连接socket接收数据->6通过获取的已完成连接socket发送数据-> 7 关闭套接字

int sockfd=socket(AF_INET,  SOCK_STREAM,  IPPROTO_TCP);
2为套接字绑定地址信息
bind(sockfd,(struct sockaddr*)&srv_addr,addrlen);
3 开始监听
listen(sockfd,backlog)---客户端连接请求到来之后在内核中新建套接字,并完成三次握手的过程
4 从已完成连接的socket循环接收和发送数据
while(1){
int newsockfd=accept(sockfd,(struct sockaddr*)&cli_addr,socklent*addrlen)
}
5 关闭和释放套接字
closed(sockfd)片

3 TCP协议的字段解析

16位源端口 16位目的端口: 实现端与端之间的数据传输
*
32位序号位 32位确认序号: 保证TCP数据的有序交付(包序管理)
*
4位首部长度: TCP报头长度(不包含数据),以4字节为单位,TCP报头大小范围:20~60字节
*
6位标志位: URG/ACK/PSH/RST/SYN/FIN
*
16位窗口大小: 用于实现滑动窗口机制
*
16位检验和: 检验接收数据与发送的数据是否一致
*
16位紧急指针: 带外数据
*
40字节选项数据: 增加弹性

4 TCP协议的三大特性

  1. 面向连接
  2. 可靠传输
  3. 面向字节流服务

5 TCP协议的连接管理中的保活机制 :删除僵尸好友

通信双方长时间(7200s)没有数据往来,每隔一段时间(75s)则会给对方发送一个报活探测数据,要求对方进行回复
1 如果收到回复,则认为连接正常
2 如果连续多次(9次)都没有收到回复,则认为连接断开
连接断开在程序中的体现:
recv 读完所有数据之后,不再阻塞(recv默认没有数据会阻塞),返回0
send 会触发异常—SIGPIPE—默认处理方式----退出进程

6 TCP协议 建立连接的过程(三次握手)
在这里插入图片描述
在这里插入图片描述
建立三次连接的详细过程如下:
1.
客户端向服务端发送SYN请求(请求建立连接,同时需要核实对方是否具备连接的条件),
2.
服务器端在listen(监听)到该连接请求之后,如果具备建立连接的条件就会向客户端发送确认报文(ACK),并询问客户端是否具备建立连接的条件(SYN),
3.
客户端收到服务器端发来的确认信息报文和询问信息后,如果自己条件具备,就会向服务端发送确认信息报文(ACK).

7 关于TCP建立连接中的一些问题

问题1 : 三次握手为什么是三次?

答: 三次握手建立连接,是为了确保通信双方都具有收发数据的能力
两次不安全(第三次握手的必要性): 如果没有第三次握手,服务端就不能保证客户端具有收发数据的能力,此时客户端是不可靠的.
四次没必要: SYN和ACK只是两个标志位,没必要分成两个报文进行发送

问题2: 握手失败如何处理?

答: 服务端等待最后一个ack报文超时后,向客户端回复RST报文 ,然后关闭释放socket 避免SYN 泛洪攻击

原因: 客户端发来的ack由于各种原因(比如ack丢失,网络延迟)如果没有传送到服务器端,TCP的超时重传机制就会产生作用,就会重新传递ACK给服务端,这时服务器端有可能收到重复的
请求,此时服务器端就会建立大量的重复连接,因此为避免这种情况,如果超时后服务器端还没有收到ack,就会向客户端发送RST(重新建立连接请求),然后与此同时关闭掉服务器端的socket ,避免SYN泛洪攻击。

8 TCP 协议断开连接的过程(四次挥手)

1 客户端向服务器端发送了断开连接请求(fin),自己进入了fin_wait(终止等待)状态,此时已经停止向服务器端发送数据
2 服务器端在收到fin请求之后,向客户端发送信息确认报文,并且进入了close_wait(关闭等待)状态,(服务器端,可能还要一些活儿没有干完,需要处理完)
3 客户端在收到服务器端发来的ACK报文后,进入了fin_wait2(状态),等待服务器端发送最终的结束报文的到来
4 服务器端在处理完手头的数据或者对数据不关心了,就会向客户端发送finsh(结束)报文,自己进入了last_wait状态,等待客户端的最后一次确认
5 客户端在收到服务器端的finsh(结束报文)后,向服务器端发送了ACK回复,并进入了time_wait状态(保证ACK能有效传递到服务器端)
6 服务器端在收到客户端发法来的ACK后,关闭释放了套接字.
7 客户端在过了2MSL之后会关闭释放套接字
在这里插入图片描述
8 关于TCP断开连接的一些问题

问题1 : 主动关闭方在收到被动关闭方的结束报文后,为什么没有直接关闭释放套接字,而是直接进入time_wait状态,等待一段时间才关闭

假设主动关闭方直接释放套接字,但是最后一次回复的ACK丢失,有可能会对后续连接造成影响
1 ACK丢失,被动关闭方会重传FIN请求报文,主动关闭方重新启动相同地址的客户端,会收到这个报文
2 主动关闭方,重新启动适用相同地址,发送SYN请求报文,有可能出现状态错误
因此主动关闭方回复最后一次ACK后需要等待一段时间
等待一段时间要干什么?
1 处理被动关闭方有可能重传的ack报文 (客户端给服务器端的ACK丢失,服务器发来重传请求,此时客户端可以对此进行回复)
2 等待两个,MSL时间,确保重传的报文消失在网络中(如果由于由于网络延迟,客户端没有将ack发给服务器端,此时服务器 端会向客户端发来重传请求,那么等待2个MSL一方面如果网络恢复了,ack会最终传递给服务器端,而服务器端又发来了RST请求,此时已经不需要重传了,因此等待2个MSL让网络中的重传请求自动消失在网络中 )

MSL: 报文的最大生命周期**,超过这个时间网络中的报文自动失效**

问题2 : 四次挥手为什么是4次?

因为被动关闭方在收到fin请求之后,立即进行ACK回复,接下来服务器端需要进行确认
缓冲区中的数据是否已经处理完毕/不关心这些数据了,才会向对方发送fin请求报文,得到ACK回复之后,则直接释放socket
因此被动关闭方的ACK和fin 不能放在一起进行回复

9 TCP协议如何保证可靠传输

1 TCP面向连接(三次握手保证可靠连接)
2 确认应答机制(每一步都走稳,步步为营)
3 超时重传机制(失误保障机制)
4 协议字段号中序号/确认信号(保证了TCP数据的有序交付)
5 协议字段中的校验和(检验接收的数据与发送的数据是否一致)

10 TCP 为保证可靠传输牺牲了一部分性能,我们如何帮TCP提高性能呢?
策略1: 滑动窗口机制
通信双方,在通信时会通过协议字段中的窗口字段协商窗口大小,告诉对方一次可以发送数据的最大数据量
当然这些数据不可能一次性全部发送,通信双方通常在第三次握手阶段,还会协商一个数据叫MSS(最大数据段大小–数据报中数据的最大长度)
发送方在发送数据人的时候会将窗口的大小分成多个大小不大于MSS大小的数据报进行发送
在这里插入图片描述
1 流量控制:
通过协议字段中的窗口字段,通知发送方能够发送的最大数据量,通过这个来限制对方的发送速度
避免发送过快,导致接收缓冲区塞满,而引起的后续的数据丢包重传.
2 快速重传:
当对方接收到第二条数据但是没有节接受到第一条,则认为第一条有可能丢失,则立即向对方连续发送第一条数据的重传请求(RST)
并将这个重传请求连续发送三次,发送方连续三次接受到重传请求,则对这条数据进行重传(连续发送三次重传请求,是为了避免由于网络阻塞而接受到延迟的数据 )
3 拥塞控制:
发送方维护一个拥塞窗口 ,控制一次发送数据的数据量,拥塞窗口以慢启动快增长的形式控制传输的数据量,起到对网络的试探的作用,
可以避免由于网络状况不好而导致的大量丢包.
每次控制一次发送的数据量,刚开始发送一点点数据,看看对方有没有收到数据,如果对方收到了数据发来了ack,则继续发送比上一次多一点数据,如果发送成功了,下次发送的时候继续加大数据 量,如果发送失败则停止发送数据,下一次再继续试探网络
在这里插入图片描述
策略2: 捎带应答机制
接收方每收到一条数据组织报文,通过报文头部的确认序号字段进行回复,这时候如果刚好有要给对方发送的数据,就会将这次的确认回复序号直接放到要发送的这条数据报头中去,可以节省一条空报文,提高传输效率(数据量越大,这种机制的优势越明显)
策略3: 延迟应答机制
数据接收方接受到数据以后,如果立即进行回复,窗口大小就会降低,导致传输吞吐率降低,降低了发送速度,这时候如果接受到数据之后,故意延迟一会进行确认回复,则有可能用户将缓冲区的数据取走,保证吞吐率.

11 TCP提供的字节流服务
send 发送的数据,会先放到socket的发送缓冲区中,然后操作系统选择合适的时间将数据发送出去
在发送数据的时候将多条数据融合成一个大包发送出去,可以提高一定的性能,并且接收方,传输层数据的交付也比较灵活,可以一点点交付,也可以一次性全部进行交付

12 字节流服务存在的粘包问题: 多条数据在缓冲区中粘连在一起(字节流服务的bug)

粘包问题的本质原因:
1 首先要明确, 粘包问题中的 “包” , 是指的应用层的数据包.
2 在TCP的协议头中, 没有如同UDP一样的 “报文长度” 这样的字段,但是有一个序号这样的字段. 站在传输层的角度, TCP是一个一个报文过来的. 按照序号排好序放在缓冲区中.
3 站在应用层的角度, 看到的只是一串连续的字节数据. 那么应用程序看到了这么一连串的字节数据, 就不知道从哪个部分开始到哪个部分, 是一个完整的应用层数据包, 于是就造成了粘包问题.
4 tcp在传输层堆数据的格式边界不敏感,不会替用户区分那条数据从哪儿开始,到哪儿结束,只关注需要向用户交付多少字节的数据.

粘包问题的解决方案 : 在应用层进行数据的边界管理

1 特殊字符: 用特殊字符间隔
2 数据定长: 通过控制数据量来控制数据格式的边界
3 不定长数据在应用头中声明数据长度: 通过在声明数据长度的方式,来告知不同数据的边界

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值