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

时间:2010-01-25 19:54:56

标签: linux exec arm sockets fork

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

最初,我使用system()来执行此外部脚本,但我们无法使用它,因为我们必须确保在分叉执行外部脚本的子项中关闭服务器套接字。登记/> 我现在自己致电fork()execvp()。我fork()然后在孩子中关闭所有服务器套接字,然后调用execvp()来执行脚本。

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

注意:仅当使用我的forkExec()函数调用脚本/客户端应用程序时才会发生这种情况。如果手动调用脚本/客户端应用程序,则socket()调用会正常执行,并且工作正常。

基于这些信息,我怀疑它是我的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;
}

FYI
操作系统:Linux
Arch:ARM32
内核:2.6.26

4 个答案:

答案 0 :(得分:11)

socket()在出错时返回-1。

返回0意味着socket()成功并为您提供文件描述符0.我怀疑您关闭的文件描述符之一具有文件描述符0,一旦关闭,下一次调用分配文件描述符的函数将返回fd 0,因为它可用。

答案 1 :(得分:7)

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

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

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

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,表示发生错误。

答案 2 :(得分:1)

不要忘记致电

waitpid()

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

答案 3 :(得分:0)

正如在另一条评论中提到的那样,你真的不应该关闭0,1或2(stdin / out / err),你可以检查以确保你不关闭它们,所以它不会被分配为当您申请新的插座时,新的fd`