一个子进程继承父进程所有文件描述符的坑

公司项目中需要在cli命令行(实质是一个Telnet连接)中通过一个类似于:http start的命令启动web服务器;自然而然地,我使用了system()这个函数。在此之前我不知道system()函数的作用机制是什么,只是知道这个可以用来启动一个进程。很顺利,http进程启动成功了,而且能够正常访问,一切看起来都是那么顺理成章;调试、上传代码,轻松而愉快。
好景不长,测试的同事发现了一个问题,在cli中启动http确实成功了,但是当cli超时退出后,无法再次正常登陆,而且无法输入,按回车键毫无反应,在shell下kill掉http进程后,cli又可以正常登陆使用了。这就很尴尬了,为什么我调试的时候没出现这个问题呢?原来我都是将cli设置成长连接不超时的。找各种原因,一开始以为cli超时会设置一些状态值或推送一些事件出来,但是,并没有。然后把我的cli设置成一分钟超时,然而,超时之后Telnet退出正常,而且也能够重新连接cli,正常登陆使用;这个就很诡异了,仔细排查,发现我的http是在shell下通过命令手动启动的。然后我也测试用cli启动http,终于,复现了问题。
查看代码,和其它的代码相比也没发现什么异常,只是使用system()函数来启动了web服务器,百度之。system()函数的调用顺序是fork()–>execv()–>waitpid(),这个时候就怀疑是不是waitpid()这里堵塞了,因为http算是cli的一个子进程,这也能解释为什么当我们kill掉http之后,cli能正常工作。于是,把system()改成了fork()+execv(),编译、调试,奇迹并没有出现,还是一样的问题。
这个时候,打开了wireshark,抓包。发现了一个诡异的现象,按我一开始的猜测,应该是cli死旋了,可是我抓包发现当我敲回车时,‘\n’发出去了,而且服务器也会了ack。好像我一开始就搞错方向了。然后我在板子上敲netstat命令,发现还有一个Telnet的连接,而且状态是已连接:
netstat中可以看到,还有一个telnet连接的状态是ESTABLISHED
又想到fork()会继承父进程的所有打开的文件描述符,会不会是因为http继承了cli的文件描述符,导致cli超时之后客户端依然和http还处于连接中,从而导致Telnet没有正常退出?于是,我在fork()之后子进程中关闭了所有的文件描述符,这一次,奇迹出现了,Telnet超时退出之后可以正常重连使用了。至此,这个问题其实应该是子进程继承了父进程打开的文件描述符(包括socket连接的文件描述符),导致Telnet没有正常退出引起的。弄明白了这个就好办了,通过/proc/$PID/fd目录可以看到进程所打开的所有的文件描述符,于是可以在fork()之后关闭所有子进程继承自父进程的文件描述符,然后再调用execv族函数来启动新的进程,这样就没有什么问题了。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值