为什么只有在重定向之前调用了 printf 才能使用 dup2 重定向到标准输出
Why redirecting to stdout with dup2 works only if printf was called before redirecting
我正在尝试编写一个程序,连接到在另一个终端上使用 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);
}
修复:
你需要告诉你的程序在写入时刷新 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
时,连接到终端的文件流将被刷新。
当缓冲区已满时,连接到套接字的文件流将被刷新。
通过在 dup2();
之前调用 printf("...\n");
,您可以强制执行第一个行为。
您的程序正在执行预期的操作,dup2(sockfd,0);
将关闭客户端程序的标准输入(即在您启动程序的终端中从键盘输入的文本),并使用 sockfd
作为你的新标准输入。引自 here:
dup2() makes newfd be the copy of oldfd, closing newfd first if necessary
为了证明这一点,请尝试以这种方式启动您的侦听套接字程序:
cat | nc -v -l 1337
在航站楼 1
- 在终端 2
中用 strace
(例如 strace a.out
)包装您的套接字客户端程序
在终端 1 中输入的文本(您在其中启动侦听端口 1337 的服务器)将通过套接字发送,在终端 2 中通过 fd 0
(现在是 [=11= 的副本)接收]), 并由于标准输出 (fd 1) 重定向到 sockfd
.
而通过套接字发回
如果您不想将文本发送回服务器而是将其显示在终端 2 上,您可能需要注释掉 dup2(sockfd,1);
。或者,您可能希望注释掉 dup2(sockfd,0);
以将客户端程序的标准输入保留在键盘上,并通过套接字发送从终端 2 输入的文本。
不确定是否回答了您的问题,但我认为 strace
+ cat
将帮助您了解如何就地管理各种文件描述符。
希望对您有所帮助!
我想说这可能是一个缓冲问题。正如建议的那样,一个常见的修复方法是刷新套接字,否则尝试将 stdout 的缓冲区设置为 0 可能会修复此行为。
setbuf(stdout, NULL);
我正在尝试编写一个程序,连接到在另一个终端上使用 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);
}
修复:
你需要告诉你的程序在写入时刷新 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
时,连接到终端的文件流将被刷新。
当缓冲区已满时,连接到套接字的文件流将被刷新。
通过在 dup2();
之前调用 printf("...\n");
,您可以强制执行第一个行为。
您的程序正在执行预期的操作,dup2(sockfd,0);
将关闭客户端程序的标准输入(即在您启动程序的终端中从键盘输入的文本),并使用 sockfd
作为你的新标准输入。引自 here:
dup2() makes newfd be the copy of oldfd, closing newfd first if necessary
为了证明这一点,请尝试以这种方式启动您的侦听套接字程序:
cat | nc -v -l 1337
在航站楼 1- 在终端 2 中用
strace
(例如 strace a.out
)包装您的套接字客户端程序
在终端 1 中输入的文本(您在其中启动侦听端口 1337 的服务器)将通过套接字发送,在终端 2 中通过 fd 0
(现在是 [=11= 的副本)接收]), 并由于标准输出 (fd 1) 重定向到 sockfd
.
如果您不想将文本发送回服务器而是将其显示在终端 2 上,您可能需要注释掉 dup2(sockfd,1);
。或者,您可能希望注释掉 dup2(sockfd,0);
以将客户端程序的标准输入保留在键盘上,并通过套接字发送从终端 2 输入的文本。
不确定是否回答了您的问题,但我认为 strace
+ cat
将帮助您了解如何就地管理各种文件描述符。
希望对您有所帮助!
我想说这可能是一个缓冲问题。正如建议的那样,一个常见的修复方法是刷新套接字,否则尝试将 stdout 的缓冲区设置为 0 可能会修复此行为。
setbuf(stdout, NULL);