tcp三次握手
客户端第一次连接服务端发送SYN报文请求,内核会将这个客户端对应的节点放到SYN队列中,直到这个客户端回应服务端的ACK后,内核会将节点移动到accept队列中,当服务器调用accept函数时,内核轮询accept队列,如有数据请求返回当前节点并分配一个fd,这个fd底层对应一个五元组来判别这个客户端是谁,确定其唯一性。
tcp控制块(tcb)保存着客户端连接的文件描述符信息,syn队列和accept队列生命周期从客户端第一次发送syn到四次挥手断开连接这个过程一直存在(服务器的状态过程listen->time_wait)。
服务端调用Listen(fd,backlog);
backlog代表:
- mac系统下代表着syn队列的长度
- Linux系统下代表着syn+accept两个队列的总长
---------------------------------------------------------------------------------------------------------------------------------
滑动窗口
客户端和服务端都为ESABLISHED状态后就可以进行send recv/read操作,思考,在进行send和recv时如何保证数据包的顺序并且完全到达和高效的传输效率:滑动窗口和ack延时让数据传输过程中即可靠又高效。
1.tcp有个滑动窗口的机制来确保对端收到数据,通过对端发送的ack确认号和头部的window size来移动数据包,左边的结束位置以acknum确定,右边的长度是以acknum+windowsize,比如:
client发送了1.2.3.4.5.6.7.8包,server端只接受到1.2.3.4回复acknum=5并携带头部的windowsize,cilent收到ack后下次发送包从5开始发送,发送的长度则是5+windowsize。
2.ack确认延时机制,让数据传输高效,如果发一个包确认一个包那么就会给带宽造成压力,接受数据包时并不及时发送ack确认,内核设置一个固定时常200ms,当接受一个数据包后重置时间开始计时,直到没有数据包超时后内核将接受来的seqnum进行排序,然后再发送顺序包的最后一个数值,让发送端重传这个值及后面的包。
---------------------------------------------------------------------------------------------------------------------------------
面试经常遇到:有了tcp可靠传输,为什么还会用udp做可靠传输?
使用udp有两种场景:
- 传输效率高,不带拥塞控制(滑动窗口控制),没有带宽限制,可用于下载
- 实时性,比如游戏视频等传输,tcp为了让数据传输更可靠内核提供了ack确认延迟,udp的实时性是属于牺牲了自身的传输效率(大量的数据包有可能导致带宽负载降低效率)。
tcp传输属于效率不低实时性也不低这么个中庸的状态,但是数据最可靠。
tcp拥塞阻塞算法
tcp三次握手后的滑动窗口的大小为初始值1
慢开始:滑动窗口的大小在未到达设置的门限值之前每次成指数增长。
拥塞控制:当滑动窗口的大小>=门限值后启动拥塞控制算法,滑动窗口每次线性增加1。
发送端在发送时会重置自己的ack_timer定时器来判断是否因为网络导致数据包未到而超时的机制来重置滑动窗口的值和sshresh阀值,此时将门限值设置为最后滑动窗口的一半,再将滑动窗口初始为1,再进行慢开始以及拥塞控制算法。
快重传:接收端发现丢包情况时立即发送ack+丢包号确认,发送端收到接收端发来三次ack+丢包号进行对应包的重传。
ttl计算:ttl为一个数据包往返确认的时间戳,也是超时重传的一个判断依据,如果网络环境不好导致ttl抖动很大则使用公式:下一个ttl计算:0.9*上一个ttl+0.1*当前ttl
---------------------------------------------------------------------------------------------------------------------------------
tcp四次挥手
问题:
- 当一端的状态为fin_wait2时,另一端不调用close(),如何终止fin_wait2。
当一端为fin_wait2状态时,属于半关闭状态,仍然可以接受对端的数据,但是不能发送,此时的状态已经不受应用程序控制,如果想要终止,只能杀死当前进程。
- TIME_WAIT有什么用。
害怕最后一次ACK丢失,当B发送FIN时会启动定时器,如果最后一次ACK丢失,B还会发送FIN,如果对端的状态不是TIME_WAIT,最后发送的ACK没有地方接受变成僵尸数据包,不知道给谁处理,TIME_WAIT的时间(默认120s,可设置)。
- 双方同时关闭。
相当于第一次的ACK丢包了,主动关闭的一端进入closing状态
- 被动关闭一方的ACK和FIN两个包合并发送
ACK包发送时会有个延时,会有可能和FIN包一并发出,主动关闭一端直接进入TIME_WAIT状态此时四次挥手就变成三次挥手了。