【问题标题】:Redirect STDOUT and STDERR to socket in C?将 STDOUT 和 STDERR 重定向到 C 中的套接字?
【发布时间】:2011-12-27 09:36:15
【问题描述】:

我正在尝试将 STDOUT 和 STDERR 重定向到套接字。

我做到了:

if(fork() == 0)
{
   dup2(newsock, STDOUT_FILENO);
   dup2(newsock, STDERR_FILENO);
   execvp();
}

不知何故,它只显示了输出的前一小部分。

例如,当我尝试执行 ls 或 mkdir 时,它显示在“mkdir”上。

有什么问题?

我尝试了以下方法,但我只能重定向 STDOUT 或 STDERR 之一

close(1);
dup(newsock);

非常感谢。

【问题讨论】:

  • @Dmitri 你能帮我解决这个问题吗?谢谢!

标签: c bash shell stdout dup


【解决方案1】:

您对dup2() 的使用看起来不错,因此问题可能出在其他地方。我用来测试的简单程序没有您遇到的问题,所以我将简单介绍一下它的核心(围绕fork()/execvp() 区域),为简洁起见省略了一些错误检查:

int    lsock, /* listening socket */
       csock; /* active connection's socket */
pid_t  cpid;  /* child process ID from fork() */
char   *cmd = "somecommand";
char   *cmd_args[] = { "somecommand",
                       "firstarg",
                       "secondarg",
                       "howevermanyargs",
                       NULL }; /* note: last item is NULL */
/*  ... 
    call socket(), bind(), listen(), etc.
    ... */

for (;;) {  /* loop, accepting connections */
  if ( (csock = accept( lsock, NULL, NULL )) == -1) exit(1);
  cpid = fork();
  if (cpid < 0) exit(1);  /* exit if fork() fails */
  if ( cpid ) {
    /* In the parent process: */
    close( csock ); /* csock is not needed in the parent after the fork */
    waitpid( cpid, NULL, 0 ); /* wait for and reap child process */
  } else {
    /* In the child process: */
    dup2( csock, STDOUT_FILENO );  /* duplicate socket on stdout */
    dup2( csock, STDERR_FILENO );  /* duplicate socket on stderr too */
    close( csock );  /* can close the original after it's duplicated */
    execvp( cmd, cmd_args );   /* execvp() the command */
  }
}

上面是一个非常基本的服务器(一次只有一个客户端)的核心,当它接收到一个连接时,它会派生一个新进程来运行一个命令,并通过套接字将它的 stderr 和 stdout 发送到客户端。希望您可以通过检查来解决您的问题——但不要只是复制代码而不了解它的作用。

首先尝试通过连接 telnet 客户端进行测试...如果它适用于 telnet 但不适用于您的客户端程序,则在您的客户端程序中查找问题。

【讨论】:

    【解决方案2】:

    您对dup2 的用法是正确的。您的写入调用并未写入您提供给它们的整个缓冲区,因为远程对等方尚未接收到数据,并且为此分配的内核缓冲区可能已满。典型的缓冲区大小为 64KB。您应该确保接收器正在接收数据,并将您的写入包装在一个循环中。或者使用MSG_SENDALLsend 系统调用。

    【讨论】:

    • 谢谢。事实证明ls 运行良好,可以列出整个目录。所以 STDOUT 工作正常。但是当它应该返回mkdir: sampledirectory already exist时,它只返回mkdir
    • 嗨,我刚看到这篇文章,我遇到了这个问题。当我将标准输出重定向到新套接字并使用 exec 时,有时它会在缓冲区中保留日期,然后会在循环之后打印它们。我到底应该怎么做?在哪里制作这个 WRITE 循环??
    【解决方案3】:

    再次阅读man dup2 页面(摘录):

     SYNOPSIS
       int dup2(int oldfd, int newfd);
    
     DESCRIPTION
       dup2() makes newfd be the copy of oldfd, closing newfd 
    

    所以应该是dup2 (STDOUT_FILENO, newsock);

    【讨论】:

    • 不,这完全是倒退。运营商希望 newsock 成为 STDOUT_FILENO
    • 但他写道:“我正在尝试将 STDOUT 和 STDERR 重定向到套接字。”我不是以英语为母语的人(法语),但“to”介词不是表示目的地吗?
    • @BasileStarynkevitch 套接字是目的地,但它是 data 的目的地——这意味着写入 stdout 或 stderr 的任何内容都应该发送到套接字。为此,他需要制作套接字的 stdout 和 stderr 副本。
    • @BasileStarynkevitch 这是dup2 手册页中的一个令人讨厌的错误。参数的顺序是相反的。
    • dup2 (STDOUT_FILENO, newsock); 将根据您引用的摘录关闭套接字。 OP 希望保持套接字打开并将输出重定向到它。为此,他需要关闭旧的标准输出并使其成为套接字的副本,dup2 (newsock, STDOUT_FILENO);
    【解决方案4】:

    我认为问题在于 stderr 和 stdout 在某些系统上是相同的

    【讨论】:

      猜你喜欢
      • 2014-07-22
      • 2011-12-26
      • 2016-02-19
      • 1970-01-01
      • 2021-10-18
      • 2012-08-07
      • 1970-01-01
      • 2022-01-18
      • 2011-07-22
      相关资源
      最近更新 更多