为什么只有在重定向之前调用了printf,才能使用dup2重定向到stdout

时间:2019-04-08 08:30:12

标签: c printf stdout dup2

我正在尝试编写一个程序,该程序连接到在另一终端上用nc -v -l 1337打开的服务器,并将stdin,stdout,stderr重定向到套接字。 意思是,另一个终端将写入套接字,并且我的程序将使用getchar()读取套接字并使用printf()进行响应。

我遇到了一些奇怪的事情-如果我注释掉首次使用printf(在dup2(sockfd,1)之前)的话,一切都会正常进行。如果不是,则打印不执行任何操作。是什么原因造成的?

int main() 
{ 
    int sockfd, connfd; 
    struct sockaddr_in servaddr, cli; 

    // socket create and varification 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    bzero(&servaddr, sizeof(servaddr)); 

    servaddr.sin_family = AF_INET; 
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    servaddr.sin_port = htons(1337); 

    connect(sockfd, (SA*)&servaddr, sizeof(servaddr));
    dup2(sockfd,0);
//---------------------------
//  printf("%s\n","hi" );
//---------------------------
    dup2(sockfd,1);
    dup2(sockfd,2);

    char buff[80]; 
    int n; 
    while(1){
        n = 0;
        while ((buff[n++] = getchar()) != '\n');
        buff[n-1] = 0;
        printf("message %s excepted\n",buff ); 
    }
    // close the socket 
    close(sockfd); 
} 

3 个答案:

答案 0 :(得分:0)

修复:

您需要在写入程序时告诉程序刷新stdout

    while(1){
        n = 0;
        while ((buff[n++] = getchar()) != '\n');
        buff[n-1] = 0;
        printf("message %s excepted\n",buff ); 

        /* ask the system to flush stdout */
        fflush(stdout);
    }

原因:(我只是在猜测)

不是所有的FILE流都被相同的缓冲。

要打印\n时,将刷新连接到终端的FILE流。

当缓冲区已满时,连接到套接字的文件流将被刷新。

通过在printf("...\n");之前调用dup2();,可以强制执行第一个行为。

答案 1 :(得分:0)

您的程序执行了预期的操作,dup2(sockfd,0);将关闭客户端程序的标准输入(即,您在启动程序的终端中从键盘输入的文本),并使用{{1 }}作为新的标准输入。引自here

  

dup2()使newfd成为oldfd的副本,必要时先关闭newfd

要证明这一点,请尝试以这种方式启动您的监听套接字程序:

  • sockfd在1号航站楼
  • 在终端2中用cat | nc -v -l 1337(例如strace)包装套接字客户端程序

在终端1(您启动服务器侦听端口1337的地方)中键入的文本将通过套接字发送,并通过strace a.out在终端2中接收(现在是fd 0的副本) ,并且由于将标准输出(fd 1)重定向到sockfd而通过套接字发送回了。

如果您不想将文本发送回服务器,而是将其显示在终端2上,则可能要注释掉sockfd。另外,您可能希望注释掉dup2(sockfd,1);,以将客户端程序的标准输入保留在键盘上,并通过套接字将从端子2输入的文本发送出去。

不确定是否能回答您的问题,但是我认为dup2(sockfd,0); + strace将帮助您了解如何管理适当的各种文件描述符。

希望这会有所帮助!

答案 2 :(得分:0)

我会说这可能是一个缓冲问题。一个常见的解决方法是,建议刷新套接字,否则尝试将stdout的缓冲区设置为0可能会解决此问题。

setbuf(stdout, NULL);