c - 将轮询函数与缓冲流一起使用

标签 c exec fork polling

我正在尝试使用 poll 实现客户端-服务器类型的通信系统C中的函数,流程如下:

  1. 主程序派生一个子进程
  2. 子进程调用exec函数执行some_binary
  3. parent 和 child 交替向对方发送消息,发送的每条消息取决于收到的最后一条消息。

我尝试使用 poll 来实现它,但遇到了问题,因为子进程缓冲了它的输出,导致我的 poll 调用超时。这是我的代码:

int main() {
char *buffer = (char *) malloc(1000);
int n;

pid_t pid; /* pid of child process */

int rpipe[2]; /* pipe used to read from child process */
int wpipe[2]; /* pipe used to write to child process */
pipe(rpipe);
pipe(wpipe);

pid = fork();
if (pid == (pid_t) 0)
{
    /* child */

    dup2(wpipe[0], STDIN_FILENO);
    dup2(rpipe[1], STDOUT_FILENO);
    close(wpipe[0]); close(rpipe[0]);
    close(wpipe[1]); close(rpipe[1]);
    if (execl("./server", "./server", (char *) NULL) == -1)
    {
        fprintf(stderr, "exec failed\n");
        return EXIT_FAILURE;
    }       
    return EXIT_SUCCESS;
}
else
{
    /* parent */

    /* close the other ends */
    close(wpipe[0]);
    close(rpipe[1]);

    /* 
      poll to check if write is good to go 
                This poll succeeds, write goes through
        */
    struct pollfd pfds[1];
    pfds[0].fd = wpipe[1];
    pfds[0].events = POLLIN | POLLOUT;
    int pres = poll(pfds, (nfds_t) 1, 1000);
    if (pres > 0)
    {
        if (pfds[0].revents & POLLOUT)
        {
            printf("Writing data...\n");
            write(wpipe[1], "hello\n", 6);
        }
    }

    /* 
        poll to check if there's something to read.
        This poll times out because the child buffers its stdout stream.
    */
    pfds[0].fd = rpipe[0];
    pfds[0].events = POLLIN | POLLOUT;
    pres = poll(pfds, (nfds_t) 1, 1000);
    if (pres > 0)
    {
        if (pfds[0].revents & POLLIN)
        {
            printf("Reading data...\n");
            int n = read(rpipe[0], buffer, 1000);
            buffer[n] = '\0';
            printf("child says:\n%s\n", buffer);
        }
    }

    kill(pid, SIGTERM);
    return EXIT_SUCCESS;
}
}

服务器代码很简单:

int main() {
    char *buffer = (char *) malloc(1000);

    while (scanf("%s", buffer) != EOF)
    {
        printf("I received %s\n", buffer);
    }   
    return 0;
}

如何防止 poll 调用因缓冲而超时?

编辑:

我希望程序即使在 execed 二进制文件是外部的情况下也能正常工作,即我无法控制代码 - 就像 unix 命令,例如 catls

最佳答案

您的代码中似乎有两个问题。 “标准输出”默认缓冲, 所以服务器应该明确地刷新它:

printf("I received %s\n", buffer);
fflush(stdout);

并且主程序在尝试读取时不应注册POLLOUT (但您可能想注册 POLLERR):

pfds[0].fd = rpipe[0];
pfds[0].events = POLLIN | POLLERR;

通过这些修改,您可以获得预期的输出:

$ ./main
Writing data...
Reading data...
child says:
I received hello

一般来说,还应该检查poll()的返回值,如果有则重复调用 必要的(例如,在系统调用中断或超时的情况下)。

关于c - 将轮询函数与缓冲流一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20581466/

相关文章:

c - 为什么这个 Bison 代码会产生意想不到的输出?

c - Linux C 中的时间返回值 0

exec - java.io.IOException : Cannot run program error=2, 没有这样的文件或目录

php - 从 php 运行 zenity

在内核中调用 do_fork

c - 父进程在子进程之前执行,如何通过信号量强制相反?

c++ - 为什么 system() 失败并显示错误代码 127?

c - 用不同的编程结构替换 `goto`

struct proc 中的starttime 与solaris 中的struct psinfo_t 的比较

java - 如何从 Jython 执行交互式 shell?