linux系统端口占用和close-on-exec机制

23 篇文章 0 订阅
17 篇文章 0 订阅

一直以来,在处理linux服务器的过程中,经常会遇到一个问题,有时候kill掉进程之后,端口被占用,新的进程一直起不来,等待很久也不能启动新进程,总是提示端口被占用,只有重启机器才能恢复正常,这个简直是个灾难,

查了一些资料,了解了如何查看端口占用情况和处理方法。

1、使用netstat命令查看端口占用情况。

  2、我们还需要知道是什么程序占用,加上-p参数

3、如果比较多的时候我们也可以用grep过滤一下

4、然后kill掉占用端口的进程即可,正常情况下就可以启动新进程了

好了,这样我们就解决了令人烦恼的端口占用问题了。

不过我却遇到了另一个问题,我的代码使用了父子进程,kill掉父进程后,fork出来的子进程却占用了父进程监听的端口,必须把子进程也kill掉才能启动。

        父进程监听一个端口后,fork出一个子进程,然后kill掉父进程,再重启父进程,这个时候提示端口占用,用netstat查看,子进程占用了父进程监听的端口。

        原理其实很简单,子进程在fork出来的时候,使用了写时复制(COW,Copy-On-Write)方式获得父进程的数据空间、 堆和栈副本,这其中也包括文件描述符。刚刚fork成功时,父子进程中相同的文件描述符指向系统文件表中的同一项(这也意味着他们共享同一文件偏移量)。这其中当然也包含父进程创建的socket。

        接着,一般我们会调用exec执行另一个程序,此时会用全新的程序替换子进程的正文,数据,堆和栈等。此时保存文件描述符的变量当然也不存在了,我们就无法关闭无用的文件描述符了。所以通常我们会fork子进程后在子进程中直接执行close关掉无用的文件描述符,然后再执行exec。

        但是在复杂系统中,有时我们fork子进程时已经不知道打开了多少个文件描述符(包括socket句柄等),这此时进行逐一清理确实有很大难度。我们期望的是能在fork子进程前打开某个文件句柄时就指定好:“这个句柄我在fork子进程后执行exec时就关闭”。其实时有这样的方法的:即所谓 的 close-on-exec。

        回到我们的应用场景中来,只要我们在创建socket的时候加上SOCK_CLOEXEC标志,就能够达到我们要求的效果,在fork子进程中执行exec的时候,会清理掉父进程创建的socket。

#ifdef WIN32
	SOCKET ss = ::socket(PF_INET, SOCK_STREAM, 0);
#else
	SOCKET ss = ::socket(PF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
#endif
当然,其他的文件描述符也有类似的功能,例如文件,可以在打开的时候使用O_CLOEXEC标识( linux 2.6.23才开始支持此标记 ),达到和上面一样的效果。或者使用系统的fcntl函数设置FD_CLOEXEC即可。

//方案A
int fd = open(“foo.txt”,O_RDONLY);
int flags = fcntl(fd, F_GETFD);
flags |= FD_CLOEXEC;
fcntl(fd, F_SETFD, flags);
//方案B,linux 2.6.23后支持
int fd = open(“foo.txt”,O_RDONLY | O_CLOEXEC);
好了,现在我们终于可以完美的解决端口占用这个令人烦恼的问题了。

转载:

http://blog.csdn.net/ljxfblog/article/details/41567419

http://blog.csdn.net/ljxfblog/article/details/41680115

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值