关闭子进程中打开的套接字 [英] Close opened sockets in child process

查看:31
本文介绍了关闭子进程中打开的套接字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 SIP 服务器(守护进程),它正在监听 tcp 套接字 5060.现在在这个父进程中,我创建了一个子进程并在子进程中做一些事情.现在,当我在父进程中关闭这个 tcp 套接字并尝试再次创建时会发生什么(假设我在这个服务器上禁用和启用 SIP),创建这个套接字会给我错误.我已经调试了这个问题并找到了根本原因.根本原因是在创建 child 时,它从 parent 继承(获取副本)所有打开的 fd/sockets.当父关闭 tcp 套接字时,它仍然在子中打开(ref_counter!=0),因此我无法在父中再次打开套接字!!

I have a SIP server (daemon) which is listening on tcp socket 5060. Now in this parent process I create a child process and do something in child. Now, What happens is when I close this tcp socket in parent process and try to create again (Lets say I am disabling and enabling SIP on this server), creating this socket gives me error. I have debugged this issue and found the root-cause. Root-cause is when child is created it inherits (gets a copy of) all the opened fd/sockets from parent. when parent closes the tcp socket it still opened in child (ref_counter!=0) and thus I cant open the socket again in parent!!

现在,我想要的通用解决方案是 - 一旦子进程启动,它就会检查任何打开的 fd(IPv4/TCP 类型)并关闭它们,以便该子进程对父进程没有副作用.如何在 C-unix 中做到这一点?我已经考虑在 system(lsof | grep | awk) 的方向上做并获取文件描述符,但是我该如何关闭它们?关闭孩子的套接字的任何其他解决方案?有没有一种方法可以传递端口号并且它给了我已经创建的 fd ?

Now, the generic solution i want is - As soon as a child process is started it checks any opened fd (of type IPv4/TCP) and close them so that there is no side effect of this child process on parent. How can this be done in C-unix ? I have contemplated about doing in the direction of system(lsof | grep | awk) and get the file descriptors, but then how do i close them ? Any other solution to close the socket in child ? Is there a method where I can pass port number and it gives me already created fd ?

我不想要的解决方案是(这对我没有帮助)-
1.在父进程中,最初在创建带有某些标志的tcp套接字时,它们不会被子进程复制.(我无法修改父级中的套接字创建)!2. 在创建子进程时将文件描述符从父进程传递给子进程.我不能那样做,因为我没有那个 fd.解决方案必须是需要放在子进程中的东西!

Solution which I dont want are (Which will not be helpful for me ) -
1. In parent process, initially while creating tcp socket with some flag so that they are not copied by child. (I can not modify that socket creation in parent)! 2. Passing file descriptor from parent to child at the time of creation of child process. I can not do that as I dont have that fd. The solution has to be something which needs to be put in child process!

谢谢

推荐答案

这里有一种方法可以确定您的孩子的文件描述符是否为套接字.

Here is a way to determine in your child whether your file descriptors are sockets.

由于孩子将继承 fd 表,只需遍历 FD 测试每个表.以下程序中的子进程通过 getrlimit 获取 fd 表的最大大小,并遍历表确定每个文件描述符是否 (a) 打开,(b) 套接字,如果是 (c)如果是监听套接字.父进程只是在 fork 之前打开一个监听和常规套接字(用于测试目的),然后等待子进程.

Since the child is going to inherit the fd table, just iterate through the FDs testing each one. The child in the following program gets the max size of the fd table via getrlimit and iterates through the table determining if each file descriptor is (a) open, (b) a socket and if so (c) if it is a listening socket. The parent just opens a listening and regular socket (for test purposes) before forking and then waiting on the child.

您应该能够使用此大纲来实现您的目标,而无需求助于 awk 等.

You should be able to use this outline to accomplish your goal without resorting to awk and the like.

#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <string.h>
#include <netdb.h>


int isListeningSocket(int fd)
{
    int retval;
    socklen_t len = sizeof(retval);

    if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &retval, &len) != -1)
        if (retval)
            return(1);

    return(0);
}

int main (int argc, char *argv[])
{
    //create a listening socket
    int lsock = socket(AF_INET,SOCK_STREAM, 0);

    struct sockaddr_in serverinfo;
    memset(&serverinfo, '0', sizeof(serverinfo));
    serverinfo.sin_family=AF_INET;
    serverinfo.sin_port=htons(atoi("9999"));
    serverinfo.sin_addr.s_addr=INADDR_ANY;

    int ret;

    if ((ret = bind(lsock,(struct sockaddr *) &serverinfo, sizeof(serverinfo))) == -1)
    {
        perror("bind");
        exit(1);
    }

    if ((ret = listen(lsock,1000)) == -1)
    {
        perror("listen");
        exit(1);
    }

    //create a regular socket
    int rsock = socket(AF_INET,SOCK_STREAM, 0);

    int pid = fork();

    if (pid == -1)
    {
        perror("fork");
        exit(1);
    }

    if (pid) //parent
    {
        wait(NULL);
        exit(0);
    }

    //child ----------

    struct rlimit rlim;

    if ((ret = getrlimit(RLIMIT_NOFILE, &rlim)) == -1)
    {
        perror("getrlimit");
        exit(1);
    }

    int maxFD = rlim.rlim_cur;

    for (int i = 0; i < maxFD; ++i)
    {
       struct stat statbuf;

       if (fstat(i, &statbuf) == -1)
           if (errno == EBADF)
           {
               printf("file descriptor %d is not open\n", i);
               continue;
           }
           else
           {
               perror("fstat");
               exit(1);
           }

       if (S_ISSOCK(statbuf.st_mode))
           if (isListeningSocket(i))
              printf("file descriptor %d is a LISTENING socket\n", i);
           else
               printf("file descriptor %d is a REGULAR socket\n", i);
       else
           printf("file descriptor %d is NOT a socket\n", i);
    }

    return 0;
}

这篇关于关闭子进程中打开的套接字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆