当前位置:网站首页>TCP相关面试常问
TCP相关面试常问
2022-08-03 03:28:00 【强尼爆紫】

哪个函数控制了三次握手的连接
没有哪个具体的函数控制了连接这种说法,客户端使用connect函数(udp中的connect不进行握手过程)将ip和port拷贝到tcp协议栈中,具体的三次握手连接是在协议栈中进行的,当第一次握手成功时,服务端会生成一个相应结点,这个结点保存在半连接队列中,它能够表示一个tcp连接的11个状态,sendbuf,recvbuf也是这个结点的一部分,每个数据包都包含了五元组的信息,故第三次握手时可以通过五元组信息在半连接队列中找到对应结点放入全连接队列中(注意这里的转移过程不是拷贝)调用accept函数会为之分配一个fd,可以用这个fd来表示它。 这个结点的生命周期一直到通信结束释放。
其实tcp通信的实体就是这个结点:它还有其他的称呼,tcp控制块或者tcb。
这里可能大家就有疑问了,那listen()函数用来干什么,listen是用来监听服务端套接字的 (只有监听着这个套接字才能收到客户端发送的连接请求) 保证客户端可以正常与服务端建立三次握手,同时使用了listen函数后也能够在协议栈中判断连接数量来决定是否接受新的连接请求。
半连接队列中结点的生命周期:当第二次握手得不到响应,一直重传第二次握手,到达一定次数后就会释放这些结点资源
为什么要三次握手:
第一次握手:Client什么都不能确认,Server确认了对方发送正常,自己接收正常
第二次握手:Client确认了:自己发送、接收正常,对方发送正常、接收正常;Server确认了:对方发送正常,自己接收正常
第三次握手:Client确认了:自己发送、接收正常,对方发送正常接收正常;Server 确认了:对方发送正常,接收正常,自己发送正常,接收正常。
为什么两次握手不行,假设Client给Server发送一个连接请求过去(第一次握手),但由于网络原因,迟迟没有到达Server端,所以Client端迟迟收不到对方的ACK回应(第二次握手),这时假设Client不想建立本次连接了,但这个由于网络延迟等原因发送的请求建立包(第一次握手)又到达了Server端,对于Client端来说这是一个没用了的请求连接,但Server端会单方面建立这次连接。

有发送消息的步骤的函数:connect , send, close, shutdown
recv看似收到消息后会回复ack确认,但实际这种现象是协议中对收到数据的自我回应,不算在上边。
1:大量time_wait 原因:由图可看出,只有主动发起close的一端才会有time_wait阶段,服务器如果出现大量time_wait,说明是程序中的哪个位置设置不当,服务器主动close了,这时候应该检查服务器程序逻辑代码
2:大量close_wait原因:当recv() == 0,说明对方发起了close断开连接,按照正常情况我们应该直接close来关闭连接,但如果当recv() == 0 出现时,我们在这种情况下还有很多业务代码要处理,这些业务代码就会耽搁close的时间,导致迟迟不能close。
if(recv == 0) {
//假设很多业务逻辑代码
close(fd);
}
正确做法,要不直接close(fd),要么另外开一个线程,去执行这些业务逻辑代码,异步实现。
3:大量fin_wait2
当遇到这种情况,与迟迟收不到对方的close有关,fin_wait1和fin_wait2一样,没有其他方式彻底关闭本次连接(因为在它们主动调用了close之后就一直在等待对方的回应),这个时候只有唯一的办法就是使用kill 来关闭连接。
4:epollrdhup和epollhup
当对方关闭写端时,我方触发EPOLLRDHUP事件。
当对方读写端都关闭,我方触发EPOLLHUP事件,但实际上我们只需要知道对方的读端关闭,就会触发EPOLLHUP,(因为一个连接的正常关闭都是先对方关闭写端,我方收到消息后关闭读端,想一想FIN断开连接的过程。)这也是为什么有EPOLLHUP,EPOLLRDHUP,但没有EPOLLWRHUP的原因,因为没必要
延申:SIGPIPE当往一个读端关闭的管道或socket写入数据,触发SIGPIPE信号,errno被设置为EPIPE。跟EPOLLHUP类似的效果。
5:列举read(recv) 和 write(send) 不同的情况
6:四次挥手后等待2MSL作用:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rBMVkFLm-1659455527995)(C:\Users\ASUS\Pictures\博客图片\20180208112533496.jpg)]
MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃
第一点:确保四次挥手的完成,我们要知道TCP有超时重传机制,在发送一个数据包后(这里假设是第三次挥手的数据包),若在规定的时间内未收到确认包,则会认为数据包丢失,重新发送一次数据包;
在此情况下(客服端向服务端主动发起关闭),假设服务端设置了RTO(Retransmission Time Out,超时重传时间)是2MSL(这个2MSL和四次挥手后的2MSL不是同一个,只是刚好时间长度一样)。服务端发送的FIN+ACK包(第三次挥手)在MSL的最后一个时刻传输到了客户端,而客户端回发了ACK包,此时客户端开始了TIME-WAIT(这里说的就是四次挥手后的2MSL等待);如果这个ACK包经过MSL还未发送到,此时服务端已经超过2MSL为收到ACK包的回应了,服务端就超时重传FIN+ACK包(第三次挥手),**注意注意:这种极端情况下,当服务端超时重传(第二次发送第三次挥手),对于客户端四次挥手后等待的2MSL来说,它从开始等待到现在这个时刻,已经过去了1MSL,**第二次发送的第三次挥手的生存时间最大是1MSL,所以如果不出意外,客户端四次挥手后等待的2MSL(目前还需等待1MSL)内一定可以收到对方的重传(第二次发送第三次挥手)。
如果第二次发送第三次挥手由于网络等原因还是失败了,对于客户端来讲,四次挥手后等待的2MSL并没有收到任何重传,所以客户端进入close状态,但是服务端也不会傻傻的一直等着,有一个保护机制, FIN 报文的重传次数是受限的,具体由 tcp_orphan_retrie这个参数决定。服务端会重试一段时间,重试次数达到限制,服务端就主动断开了。【达到重试次数时,相当于服务端那边认为已经是出了什么问题,不可能收到这个ACK包,主动断开了】
第二点:防止新的tcp连接收到上一次由于网络等原因迟到的数据包,如果没有这个2msl等待时间(在2msl等待期间,这个端口在默认情况下不能被再使用,不过可以在setsockopt函数中设置SO_REUSEADDR选项,从而不必等待2MSL时间结束再使用此端口。),假如下一次建立的新连接刚好使用了与上一次一样的端口号,若上一次连接中,对方有由于网络等原因迟到的数据包,有可能将会被这次新的连接接收到而引起错误,每个数据包都是有最大生存时间的,等待2msl确保新的连接不会收到上一次的由于网络等原因迟到的数据包。
边栏推荐
猜你喜欢
随机推荐
vscode hide activity bar
爆肝22个ES6知识点
成都高新南区 高新西区 东部新区 多边形范围点位 AOI 高德
IDEA如何创建同级工程
金仓数据库 OCCI 迁移指南(5. 程序开发示例)
DMA 的工作方式
关于 Redis 必问面试题,你知道哪些?
15【背景 渐变色】
ClickHouse uninstall and reinstall
PyTorch installation - error when building a virtual environment in conda before installing PyTorch
(2022牛客多校五)H-Cutting Papers(签到)
Go新项目-编译项目的细节(4)
金仓数据库 Pro*C 迁移指南(3. KingbaseES Pr*oc 对 Oracle Pro*c 的兼容)
Jincang Database Pro*C Migration Guide ( 5. Program Development Example)
Chapter 8 Character Input Output and Input Validation
中原银行实时风控体系建设实践
iScroll系列之下拉刷新 + 上拉加载更多
【数据分析】基于MATLAB实现SVDD决策边界可视化
金仓数据库 Pro*C 迁移指南( 4. KingbaseES 的 Pro*C 迁移指南)
【 original 】 Auto. Js the get and post case








