今天在使用system()函数启动apache时,出现了一个问题,程序伪代码如下:
int sock = createSocket();
bindSocket(sock,1111);
listen();
while((int clisock = accept())> 0)
{
string strRecvBuff = recvFromClient(clisock);
system("./apachectl start");
close(clisock);
}
当执行启动apache的任务时,system正常结束,在当前进程中关闭了和客户端连接的socket,但是此时在用系统中用netstat -anp | grep 1111命令查看,发现有一个tcp连接始终连接到系统的1111端口,并且资源为apache进程所拥有。
为什么会出现这种情况呢?首先要知道system函数的原理,system函数就是fork + exec,其原理是在当前进程中fork()一个新的进程,并在子进程中调用exec替换掉程序段。现在返回头看看上面的那段代码,服务器accept以一个客户端连接,并从客户端读取用户控制信息,当发现命令是启动apache时,调用system函数运行 apachectl start 命令。这时会发生什么事情呢?fork的子进程中把当前的网络连接 “复制” 出一份,由于apache是当前程序的子进程,故apache时钟占用这个连接和端口,即使父进程已经退出了、并且在父进程中关闭了socket,但是网络连接仍然在。
解决这个问题的方法其实也很简单,利用fcntl函数,设置socket遇到exec函数族的时候自动关闭,这样就不会造成socket泄漏了。
具体代码为,在创建socket以后,设置:
int val = 0;
val = fcntl(clifd,F_GETFL,0) ;
fcntl(clifd,F_SETFD,val|FD_CLOEXEC)
这样就可以了