代码之家  ›  专栏  ›  技术社区  ›  Steve Lazaridis

socket()在C客户端服务器应用程序中返回0

  •  8
  • Steve Lazaridis  · 技术社区  · 15 年前

    我正在开发一个包含几个服务器套接字的应用程序,每个套接字在一个唯一的线程中运行。
    外部实用程序(脚本)由其中一个线程调用。此脚本调用一个实用程序(客户机),该实用程序将消息发送到其中一个服务器套接字。

    最初,我用 system() 要执行这个外部脚本,但我们无法使用它,因为我们必须确保在分叉以执行外部脚本的子级中关闭服务器套接字。
    我现在打电话 fork() execvp() 我自己。我 Frk() 然后在这个孩子身上,我关闭所有的服务器套接字,然后调用 执行程序() 执行脚本。

    现在,一切都很好。问题是脚本有时会向服务器应用程序报告错误。脚本通过调用另一个应用程序(客户端)来发送这些错误,该应用程序打开TCP套接字并发送适当的数据。我的问题是客户端应用程序的值为 0 返回的 socket() 系统调用。

    注意:这只在使用my forkeexec()函数调用脚本/客户端应用程序时发生。如果手动调用脚本/客户端应用程序, 套接字() 呼叫执行正常,工作正常。

    基于这些信息,我怀疑这是我下面的fork()execvp()代码中的内容…有什么想法吗?

    void forkExec()
    {    
        int stat;
    
        stat = fork();
        if (stat < 0)
        {
            printf("Error forking child: %s", strerror(errno));
        }
        else if (stat == 0)
        {
            char *progArgs[3];
    
            /*
             * First, close the file descriptors that the child 
             * shouldn't keep open
             */
            close(ServerFd);
            close(XMLSocket);
            close(ClientFd);
            close(EventSocket);
            close(monitorSocket);
    
            /* build the arguments for script */
            progArgs[0] = calloc(1, strlen("/path_to_script")+1);
            strcpy(progArgs[0], "/path_to_script");
            progArgs[1] = calloc(1, strlen(arg)+1);
            strcpy(progArgs[1], arg);
            progArgs[2] = NULL; /* Array of args must be NULL terminated for execvp() */
    
            /* launch the script */
            stat = execvp(progArgs[0], progArgs);
            if (stat != 0)
            {
                printf("Error executing script: '%s' '%s' : %s", progArgs[0], progArgs[1], strerror(errno));
            }
            free(progArgs[0]);
            free(progArgs[1]);
            exit(0);
        }
    
        return;
    }
    

    客户端应用程序代码:

    static int connectToServer(void)
    {
    int socketFD = 0;
    int status;
    struct sockaddr_in address;
    struct hostent* hostAddr = gethostbyname("localhost");
    
    socketFD = socket(PF_INET, SOCK_STREAM, 0);
    

    上面的调用返回0。

    if (socketFD < 0)
    {
        fprintf(stderr, "%s-%d: Failed to create socket: %s", 
                                    __func__, __LINE__, strerror(errno));
        return (-1);
    }
    
    memset(&address, 0, sizeof(struct sockaddr));
    address.sin_family = AF_INET;
    memcpy(&(address.sin_addr.s_addr), hostAddr->h_addr, hostAddr->h_length);
    address.sin_port = htons(POLLING_SERVER_PORT);
    
    status = connect(socketFD, (struct sockaddr *)&address, sizeof(address));
    if (status < 0)
    {
        if (errno != ECONNREFUSED)
        {
            fprintf(stderr, "%s-%d: Failed to connect to server socket: %s",
                       __func__, __LINE__, strerror(errno));
        }
        else
        {
            fprintf(stderr, "%s-%d: Server not yet available...%s",
                       __func__, __LINE__, strerror(errno));
            close(socketFD);
            socketFD = 0;
        }
    }
    
    return socketFD;
    }
    

    供参考
    操作系统:Linux
    ARM32:ARM32
    内核:2.626

    4 回复  |  直到 9 年前
        1
  •  11
  •   R Samuel Klatchko    15 年前

    socket()出错时返回-1。

    返回0表示socket()成功,并为您提供了文件描述符0。我怀疑关闭的文件描述符中有一个文件描述符0,一旦关闭,对分配了文件描述符的函数的下一个调用将返回fd 0,因为它是可用的。

        2
  •  7
  •   nos    15 年前

    值为0的套接字很好,这意味着stdin已关闭,这将使fd 0可供重用——例如通过套接字。

    可能是您在forkexec()子路径(xmlsocket/serverfd)中关闭的文件描述符之一,它是fd 0。这将在关闭fd 0的情况下启动子进程,当您从命令行运行应用程序时不会发生这种情况,因为fd 0已经作为shell的stdin打开。

    如果希望套接字不是0、1或2(stdin/out/err),请在所有close()调用之后在forkeexec()函数中调用以下内容

    void reserve_tty()
    {
      int fd;
    
      for(fd=0; fd < 3; fd++)
        int nfd;
        nfd = open("/dev/null", O_RDWR);
    
        if(nfd<0) /* We're screwed. */
        continue;
    
        if(nfd==fd)
        continue;
    
        dup2(nfd, fd);
        if(nfd > 2)
         close(nfd);
    
    }
    

    检查套接字是否返回-1,这意味着发生了错误。

        3
  •  1
  •   Rob Wells    15 年前

    别忘了打电话给

    waitpid()
    

    “明显问题模式”结束。我在这里假设了一点,但是您没有对fork()调用返回的pid做任何操作。(-)

        4
  •  0
  •   Adel    9 年前

    正如在另一条注释中提到的,您确实不应该关闭0、1或2(stdin/out/err),您可以进行检查以确保不关闭它们,这样在您请求新的套接字时,它不会被分配为新的fd's。