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

发布于 2024-08-18 17:55:41 字数 3010 浏览 5 评论 0原文

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

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

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

注意:仅当使用我的 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;
}

仅供参考
操作系统:Linux
架构:ARM32
内核:2.6.26

I'm working on an application that contains several server sockets that each run in a unique thread.
An external utility (script) is called by one of the threads. This script calls a utility (client) that sends a message to one of the server sockets.

Initially, I was using system() to execute this external script, but we couldn't use that because we had to make sure the server sockets were closed in the child that was forked to execute the external script.
I now call fork() and execvp() myself. I fork() and then in the child I close all the server sockets and then call execvp() to execute the script.

Now, all of that works fine. The problem is that at times the script reports errors to the server app. The script sends these errors by calling another application (client) which opens a TCP socket and sends the appropriate data. My issue is that the client app gets a value of 0 returned by the socket() system call.

NOTE: This ONLY occurs when the script/client app is called using my forkExec() function. If the script/client app is called manually the socket() call performs appropriately and things work fine.

Based on that information I suspect it's something in my fork() execvp() code below... Any ideas?

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;
}

Client app code:

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);

The above call returns 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
OS: Linux
Arch: ARM32
Kernel: 2.6.26

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

层林尽染 2024-08-25 17:55:41

socket() 出错时返回 -1。

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

socket() returns -1 on error.

A return of 0 means socket() succeeded and gave you file descriptor 0. I suspect that one of the file descriptors that you close has file descriptor 0 and once it's closed the next call to a function that allocated a file descriptor will return fd 0 as it's available.

浅唱々樱花落 2024-08-25 17:55:41

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

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

如果您希望套接字不是 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,这意味着发生了错误。

A socket with value 0 is fine, it means stdin was closed which will make fd 0 available for reuse - such as by a socket.

chances are one of the filedescriptors you close in the forkExec() child path(XMLSocket/ServerFd) etc.) was fd 0 . That'll start the child with fd 0 closed, which won't happen when you run the app from a command line, as fd 0 will be already open as the stdin of the shell.

If you want your socket to not be 0,1 or 2 (stdin/out/err) call the following in your forkExec() function after all the close() calls

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);

}

Check for socket returning -1 which means an error occured.

云雾 2024-08-25 17:55:41

不要忘记调用

waitpid()

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

Don't forget a call to

waitpid()

End of "obvious question mode". I'm assuming a bit here but you're not doing anything with the pid returned by the fork() call. (-:

女中豪杰 2024-08-25 17:55:41

正如另一条评论中提到的,您确实不应该关闭 0,1 或 2 (stdin/out/err),您可以进行检查以确保您没有关闭这些,因此它不会被分配为新的 fd`当你请求一个新的套接字时

As it is mentioned in another comment, you really should not close 0,1 or 2 (stdin/out/err), you can put a check to make sure you do not close those and so it will not be assigned as new fd`s when you request for a new socket

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文