前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >应用层如何强制发送RST即相关内核实现

应用层如何强制发送RST即相关内核实现

作者头像
glinuxer
发布2019-04-10 15:02:03
1.7K0
发布2019-04-10 15:02:03
举报

前几天群里有个同学问,“如何让应用层强制发送RST中止连接”,而不是通过FIN包的四次交互来关闭连接。当时,我只是凭借以往的经验,猜测使用linger选项可以做到。之所以这么猜测,完全是出于对TCP和linger的理解。

当TCP套接字正常关闭时,close会立刻返回,内核会尽力去保证把未发送的缓存发送出去——注意,是尽力保证,并没有说一定会发出去。使用linger选项时,可以设置一个延时时间。调用close时,不再立刻返回,而是尝试在设置的延时时间内,将数据发送出去。当全部发送成功,或者到达设置的超时时间时,close就会返回。注意,网上很多资料,都说在延时时间内还没有成功发送所有的数据时,close会返回错误,但这些说法网上资料都是错的。实际上不管是否在linger的时间内成功发送了所有数据,close都返回0。

回过头来,先继续咱们的原来话题。linger选项有一个特殊的情况。即开启linger选项,但是超时时间为0,这意味着内核根本不会尝试发送缓存中的数据,而是直接关闭fd。这样的处理,对于TCP来说,实际上是一种异常情况。如果仍然是正常的发送FIN包关闭连接,就等于告诉对端,我所有的数据已经发送完毕,但实际情况则不是。所以,这时就需要使用RST来中断连接,来通知对端发生了异常情况。

下面就看,应用层如何强制发送RST来中止连接的关键代码:

启用linger选项,同时linger的超时时间设置为0。完整的测试代码位于:https://github.com/gfreewind/LinuxDetails/blob/master/networks/7.tcp_send_rst/tcp_send_rst.c。

利用nc监听指定的TCP端口,然后运行测试程序,抓包如下:

可以明显的看到,在关闭TCP套接字时,应用层强制发送了RST中止连接。

任务达成!接下来就要看看内核对于linger的处理。在tcp_close函数中,

如果套接字设置了linger且lingertime值为0,那么就调用disconnect函数,即tcp_disconnect。在这个函数中,

只要tcp_need_reset(old_state)为真,就会调用tcp_send_active_reset来发送RST报文中止连接。而“已连接”的TCP状态是TCPF_ESTABLISHED,就是需要RESET的状态之一。

至此,就已经了解了设置linger选项,强制发送RST的内核实现。还剩下一点:就是开头提到的,内核没有在linger时间内发送完所有数据,会不会返回错误。

这个证据很简单。我们都不用去分析tcp_close,直接看sock_close。

其无不关心具体的套接字的实现,之间返回0。所以对于套接字的fd来说,其close永远返回0——至少到目前的linux最新内核是这样的:D

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-07-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 LinuxerPub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档