关于linux进程间的close-on-exec机制

转载请注明出处:帘卷西风的专栏(http://blog.csdn.net/ljxfblog)

前几天写了一篇博客,讲述了端口占用情况的查看和解决。

关于linux系统端口查看和占用的解决方案

大部分这种问题都能够解决,在文章的最后,提到了一种特殊情况,就是父子进程中的端口占用情况。父进程监听一个端口后,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);

好了,现在我们终于可以完美的解决端口占用这个令人烦恼的问题了。

时间: 2024-10-10 10:33:52

关于linux进程间的close-on-exec机制的相关文章

linux 进程间信号量管理程序之sem_timedwait使用

在开发过程中,有三个独立运行的程序模块,三个模块都对sqlite数据库进行读写操作.sqlite在linux共享性较差,所以需要加入互斥信号量解决三个模块访问数据库该问题.另外,在加入信号量后,信号量sem初始化为1,如果三个模块任意一个在读或写数据库时ctrl+c掉(调试过程需要),有时会造成信号量sem保持sem_wait后的值,也就是为0:这就造成了死锁. 为了解决上述情况,决定在某一个模块使用sem_timedwait(sem_t *sem,const struct timespec *

linux进程间通讯-System V IPC 信号量

进程间通信的机制--信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信--使用信号.下面就进入信号量的讲解. 一.什么是信号量 为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域.临界区域是指执行数据更新的代码需要独占式地执行.而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在

Linux进程间的通信

一.管道 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: A. 管道是半双工的,数据只能向一个方向流动: B. 需要双工通信时,需要建立起两个管道: C. 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程): D. 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中. 匿名管道的创建:该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义;因此,一

Linux进程间的通信方法

linux进程间的通信方法总结如下 通过fork函数把打开文件的描述符传递给子进程 通过wait得到子进程的终结信息 通过加锁的方式,实现几个进行共享读写某个文件 进行间通过信号通信,SIGUSR1和SIGUSR2实现用户定义功能 利用pipe进行通信 FIFO文件进行通信 mmap,几个进程映射到同一内存区 SYS IPC 消息队列,信号量(很少用) UNIX Domain Socket,常用

Linux 进程间通讯方式 pipe()函数 (转载)

转自:http://blog.csdn.net/ta893115871/article/details/7478779 Linux 进程间通讯方式有以下几种: 1->管道(pipe)和有名管道(fifo). 2->消息队列 3->共享内存 4->信号量 5->信号(signal) 6->套接字(sicket) 在这里我们看一下第一种====管道(pipe).有名管道(fifo)见其它文章. eg :我们以前学的命令 cat  file | grep  "abc

linux 进程间的通信

现在linux使用的进程间通信方式:(1)管道(pipe)和有名管道(FIFO)(2)信号(signal)(3)消息队列(4)共享内存(5)信号量(6)套接字(socket) 为何进行进程间的通信:A.数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间B.共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到.C.通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程).D.资源共享

linux进程间的通信(C): 消息队列

一.消息队列(message queue) 消息队列也是System V IPC机制之一. 消息队列与命名管道类似, 但少了打开和关闭管道方面的复杂性. 但使用消息队列并未解决我们在使用命名管道时遇到的一些问题, 如管道满时的阻塞问题. 消息队列提供了一种在两个不相关进程间传递数据的简单有效的方法. 与命名管道相比, 消息队列的优势在于,它独立于发送和接收进程而存在, 这消除了在同步命名管道的打开和关闭时可能产生的一些困难. 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法. 而且,

Linux 进程间通讯详解一

进程间的通讯 两台主机间的进程通讯 --socket 一台主机间的进程通讯 --管道(匿名管道,有名管道) --System V进程间通信(IPC)包括System V消息队列,System V信号量,System V共享内存 --socket 进程间共享内存的三种方式 --文件系统(通过系统调用读写磁盘文件,scoket)==>最慢 --Linux内核共享信息(直接在Linux内核中1进行通讯,比如管道,消息队列,信号)==>中等 --共享内存区(在自己进程内开辟一块内存,映射到系统内存)=

Linux 进程间通讯详解二

消息队列 --消息队列提供了本机上从一个进程向另外一个进程发送一块数据的方法 --每个数据块都被认为有一个类型,接收者进程接收的数据块可以有不同的类型值 --消息队列也有管道一样的不足,就是每个消息的最大长度是由上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI) 消息大小的三大限制 cat /proc/sys/kernel/msgmax --最大消息的长度限制(65536) cat /proc/sys/kernel/msg

linux进程间的网络通信

一.进程是如何进行网络通信的?socket通信的过程? 同一机器上的不同进程之间的通信方式有很多种,主要使用消息传递或共享内存.而跨网络的进程是几乎都是使用socket通信,例如web服务器,QQ. socket即是一种特殊的文件,操作系统提供了一些socket函数就是对其进行的操作(读/写IO.打开.关闭),进程间的通信就是靠读写各自的socket完成的. 通信的过程 server: 使用socket()系统调用创建一个指定类型和协议套接字 使用bind()系统调用给创建的socket命名,这