【问题标题】:Change File Descriptor to pipe STDOUT to a Socket?更改文件描述符以将 STDOUT 传输到套接字?
【发布时间】:2026-01-13 08:10:02
【问题描述】:

我打开了一个套接字,用于连接客户端和服务器。

我正在实现远程执行,因此我想更改文件描述符表,这样通常会转到标准输出的调用实际上会通过套接字输出到客户端。

现在我有服务器分叉,然后使用 system() 命令执行任何命令。

如何操作文件描述符表?

这是我正在使用的代码:

我正在使用选择。我正在使用的套接字是接受调用返回的套接字(这都是服务器端)。

            dup2(S,1);

            int retval = fork();
            if (retval > 1)
            {
            system(receive.text);
            return 0;
            }

现在这样做的结果是,没有文本被打印到服务器(因此它显然没有连接到服务器的标准输出中),但客户端上也没有显示任何内容)。

我是否需要在客户端做更多的事情才能解决这个问题(比如 recv() 调用?),我是否使用了正确的套接字?

谢谢。

【问题讨论】:

    标签: c file-io client-server file-descriptor


    【解决方案1】:

    通常的机制是dup2(2):

    #include <unistd.h>
    
    int dup(int oldfd);
    int dup2(int oldfd, int newfd);
    

    dup(2) 调用会将给定的文件描述符复制到编号最小的打开文件描述符。这是历史机制,仍然有效,但指定文件描述符编号并不容易。因此引入了dup2(2) 以允许同时指定两个文件描述符。

    你可以这样使用它:

    int s = /* connect() or accept() */
    int ret = dup2(s, 1);
    /* exec() */
    

    【讨论】:

    • @blackbinary,你让我后悔只使用整数而不是STDOUT_FILENO :) -- 0 是标准输入,1 是标准输出,2 是标准错误;由于 shell 重定向的 2&gt;&amp;1 样式,我发现它更容易记住——您几乎从不重定向 0,因此必须输入。 :)
    • 好的,那么我正在查看的页面有错字(有 0 而不是 1)。我将在原始帖子中发布一些代码,因为它的行为仍然不正确。
    • @Blackbinary,该页面可能还希望标准输入适用于该命令。
    【解决方案2】:

    问题是system 仅仅保留了父文件描述符,所以它不能像你想要的那样工作。你可以使用popen,但它很难看。您真的应该自己编写forkexec 代码。 system 几乎总是一个错误。

    【讨论】:

    • 啊,我认为它是等效的,我只是在节省时间。所以如果我自己分叉和执行,它应该可以工作吗?
    • 那么,如果 dup2 用于更改文件描述符,为什么我不能只使用 printf (因为现在将指向套接字)?它不起作用,但我想知道原因(而且我似乎也无法让 fork 和 exec 工作)。