gpt4 book ai didi

c - 如何在 Linux c 中的 CTRL - C 后清除标准输出

转载 作者:太空狗 更新时间:2023-10-29 12:28:00 25 4
gpt4 key购买 nike

我们不希望在用户通过 CTRL-C 中断后打印任何内容。我们已尝试在 sigInt 信号处理程序中添加 __fpurge 以及 fflush,但它不起作用。

如何立即清除缓冲的标准输出值?我遇到过几个类似的线程,但没有找到可行的解决方案。

一些附加信息:即使在添加 exit(0) 之后,在 sigInt 信号处理程序内部,缓冲区内容仍在打印,但处理器已被终止。

添加了 exit(0) 来缩小问题范围,我不想杀死处理器

我知道以上是预期行为,不确定如何避免。

最佳答案

考虑这个编辑过的例子——编辑过;这个不退出进程:

#define  _POSIX_C_SOURCE 200809L /* For nanosleep() */
#include <unistd.h>
#include <stdlib.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdio.h>

static void exit_handler(int signum)
{
int fd, result;

/* If the standard streams are connected to a tty,
* tell the kernel to discard already buffered data.
* (That is, in kernel buffers. Not C library buffers.)
*/
if (isatty(STDIN_FILENO))
tcflush(STDIN_FILENO, TCIOFLUSH);
if (isatty(STDOUT_FILENO))
tcflush(STDOUT_FILENO, TCIOFLUSH);
if (isatty(STDERR_FILENO))
tcflush(STDERR_FILENO, TCIOFLUSH);

/* Redirect standard streams to /dev/null,
* so that nothing further is output.
* This is a nasty thing to do, and a code analysis program
* may complain about this; it is suspicious behaviour.
*/
do {
fd = open("/dev/null", O_RDWR);
} while (fd == -1 && errno == EINTR);
if (fd != -1) {
if (fd != STDIN_FILENO)
do {
result = dup2(fd, STDIN_FILENO);
} while (result == -1 && (errno == EINTR || errno == EBUSY));
if (fd != STDOUT_FILENO)
do {
result = dup2(fd, STDOUT_FILENO);
} while (result == -1 && (errno == EINTR || errno == EBUSY));
if (fd != STDERR_FILENO)
do {
result = dup2(fd, STDERR_FILENO);
} while (result == -1 && (errno == EINTR || errno == EBUSY));
if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
close(fd);
}
}

static int install_exit_handler(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = exit_handler;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}

int main(void)
{
if (install_exit_handler(SIGINT)) {
fprintf(stderr, "Cannot install signal handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}

while (1) {
struct timespec t = { .tv_sec = 0, .tv_nsec = 200000000L };

printf("Output\n");
fflush(stdout);

nanosleep(&t, NULL);
}

/* Never reached. */
return EXIT_SUCCESS;
}

当进程接收到 SIGINT 信号时,它将首先刷新内核终端缓冲区中的所有内容,然后将标准流重定向到 /dev/null(即无处可去) ).

请注意,您需要通过向进程发送 TERM 或 KILL 信号来终止进程(即在另一个终端中发送 killall ./yourprogname)。


当您通过远程连接运行冗长的过程时,很多信息可能一直处于传输状态。运行该进程的本地机器和远程机器的套接字缓冲区都快满了,因此 latency可能比平常大得多 - 即使在快速 (GbE) 本地网络上,我也看到这种情况下有几秒钟的延迟。

这意味着将信号从本地机器传播到远程机器将花费可测量的时间;在最坏的情况下,以秒为单位。只有这样,远程进程才会停止输出数据。所有挂起的数据仍然必须从远程机器传输到本地机器,这可能需要相当长的时间。 (通常,瓶颈是终端本身;在大多数情况下,最小化终端会更快,这样它就不会尝试呈现它接收到的任何文本,只会在内部对其进行缓冲。)

这就是为什么 Ctrl+C 不会也不能立即停止远程输出的原因。

在大多数情况下,您将使用 SSH 连接到远程计算机。该协议(protocol)也没有可能在这里有所帮助的“清除”功能。许多人,包括我自己,都考虑过这个问题——至少我的香肠手指不小心 tab 进入可执行文件而不是类似名称的输出文件,不仅让终端充满垃圾,而且二进制文件中的特殊字符有时会将终端状态(参见例如 xterm control sequencesANSI escape codes)设置为不可恢复的状态(即 Ctrl+Z 后跟 reset Enter 不会将终端重置回工作状态;如果是这样,kill -KILL %- ; fg 将停止 Bash 中的错误命令,并取回您的终端),并且您需要断开连接,这也将终止从在后台远程运行的同一终端启动的所有进程。

这里的解决方案是使用终端多路复用器,例如 GNU screen ,它允许您在不中断现有终端连接的情况下连接到远程计算机和断开连接。 (简单来说,screen就是你在远程机器上的终端头像。)

关于c - 如何在 Linux c 中的 CTRL - C 后清除标准输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36326470/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com