TCP详解
- 特点:面向连接、可靠传输、面向字节流
面向连接:通过三次握手建立连接/四次挥手挥手断开连接以及状态的连接管理实现面向连接—tcp协议是一个有状态的协议
可靠传输:保证数据有序并可到达对端
面向字节流:可靠的、有序的、全双工、基于连接的字节流传输 - tcp协议报文格式
按序排列:
16位源端端口;16位目的端端口;32为序号;32位确认序号;
4位头部长度;6位保留位;6位标志位;16位窗口大小
16位校验和;16位紧急指针;40字节选项数据;数据
报文各部解释:
(源端/目的端)端口:负责数据传输的地址
序号/确认序号:实现tcp在传输层的包序管理–tcp有序交付数据
头部长度:计数单位为4字节,4位共可表示60字节
标志位:URG-紧急指针标志/ACK-确认回复标志/PSH-提示立即接受/RST-重置连接/SYN-连接建立请求/FIN-断开连接请求
窗口大小:滑动窗口机制–流量控制–告诉对端所能发送的最大数据量
紧急指针:指明哪些数据是紧急数据
校验和:二进制反码求和校验数据一致性
选项数据:三次握手时,协商MSS大小的数据 - tcp连接管理
双方建立套接字、绑定地址信息
三次握手开始
服:状态-LISTEN(获取客户端的连接请求)
客:状态-SYN_SENT(发送连接请求)操作-发送SYN(连接请求)
服:状态-SYN_RCVD(确认连接请求并等待对方回复)操作-发送ACK+SYN
客:状态-ESTABLISHED(连接成功,可通信)操作-发送ACK
服:状态-ESTABLISHED(连接成功,可通行)
三次握手结束
···
···
四次挥手开始
客:调用shutdown(fd,SHUT_WR)—关闭客户端写功能
客:状态-FIN_WAIT1(不再向对方发送数据)操作-发送FIN
服:状态-CLOSE_WAIT(服务端不再读,recv不阻塞且返回0)
服:调用shutdown(fd,SHUT_RD)—关闭服务端读功能
服:状态-CLOSE_WAIT(服务端不再读,recv不阻塞且返回0) 操作-发送ACK
客:状态-FIN_WAIT2(等待服务端的最后一个FIN)
服:调用shutdown(fd,SHUT_WR)—关闭服务端写功能
服:状态-LAST_ACK(服务端也不再写)操作-发送FIN
客:状态-FIN_WAIT2(等到最后一个FIN) 操作-发送ACK
服:状态-CLOSE(等一会后服务端资源释放)
客:等待一段时间后进入CLOSE(客户端资源释放)
四次挥手结束 - 可靠传输
实现可靠传输的技术:连接管理、确认应答机制、超时重传机制、协议中校验和字段、协议中序号和确认序号字段
连接管理:通过来连接管理保证双方都具有数据收发的能力
确认应答机制:接收方对于接收到的每一条数据都要进行确认回复,告诉发送方说数据我收到了–使用确认序号进行应答
超时重传机制:发送方发送数据后一段时间内没有收到确认回复,则对数据进行重传
校验和字段:校验数据一致性,不一致则要重传
序号和确认序号字段:进行包序管理,保证数据有序交付
常见问题
- shutdown/close/FIN
shutdown(fd,how)
—只关闭功能,不释放套接字资源
fd:被操作的套接字
how:SHUT_WR/SHUT_RD/SHUT_RDWR
close(fd)
–关闭套接字读写功能,释放资源
FIN包–只要关闭写端就会发送FIN包,并非表示断开连接 - 握手建立连接为什么是三次
两次不安全,四次没必要
tcp是双向通信,需要双方都确保对方在线,具有数据收发的能力
两次连接
客:发送SYN包
服:回复ACK
只保证了客户端具有发送的能力,并不确保它具有接受数据的能力
四次连接没有必要,在第一次回答时ACK与SYN结合 - 挥手断开连接为什么是四次
第一次挥手
因此当主动方发送断开连接的请求(即FIN报文)给被动方时,仅仅代表主动方不会再发送数据报文了,但主动方仍可以接收数据报文。
第二次挥手
被动方此时有可能还有相应的数据报文需要发送,因此需要先发送ACK报文,告知主动方“我知道你想断开连接的请求了”。这样主动方便不会因为没有收到应答而继续发送断开连接的请求(即FIN报文)
第三次挥手
被动方在处理完数据报文后,便发送给主动方FIN报文;这样可以保证数据通信正常可靠地完成。发送完FIN报文后,被动方进入LAST_ACK阶段(超时等待)。
第四挥手
如果主动方及时发送ACK报文进行连接中断的确认,这时被动方就直接释放连接,进入可用状态 - 客户端为什么还要有个TIME_WAIT状态
若主动方发送最后一个ACK后,被动方若没有接受到,则会超时重发第二个FIN包,导致后续连接出错
出错的两个点,主动方刚重启时接受到一个FIN包;主动方向被动方发送SYN而被动方处在LAST_ACK,收到SYN会向主动方发送RST重置连接报文
等待的时间长度为两个MSL(报文最大生存周期),重传FIN包和响应ACK两个报文,目的在于要求本次来连接的所有数据都消失,不对后续操作造成影响 - 若三次握手失败,服务端如何处理
第一种情况
客户端的SYN没到达服务端,不做任何处理
第二种情况
服务端没收到第二个ACK,则发送RST重置连接,释放当前套接字,新建套接字重新发送ACK+SYN - 服务器上出现大量的CLOSE_WAIT是什么原因
CLOSE_WAIT收到主动方的FIN包后等待程序调用close/shutdown(fd,SHUT_WR)
程序作为被动方时,在连接断开后,没有调用close关闭,释放资源
解决方法:检查代码 - 服务器上出现大量的TIME_WAIT是什么原因
TIME_WAIT 主动方,发送最后一个ACK后的状态
意味着服务器上大量主动的关闭了连接-通常出现在爬虫服务器上
解决方法:开启tcp连接重用、设置MSL时间 - TCP服务器最大并发连接数是多少
他可以同时连接的客户端数量并不受限于可用端口号,理论上一个服务器的一个端口能建立的连接数是全球的IP数*每台机器的端口数。
实际并发连接数受限于linux可打开文件数
通过#ulimit -n
查看服务的最大文件句柄数,通过ulimit -n xxx
修改 xxx是你想要能打开的数量 - 四种情况会发送RST包:
1、端口未打开
2、请求超时
3、提前关闭
4、在一个已关闭的socket上收到数据
部分回答来源其他博客,若有问题请联系我