如何捕获Control+D信号?
- 2024-10-10 08:38:00
- admin 原创
- 73
问题描述:
我想在我的程序中捕获Ctrl
+D
信号并为其编写一个信号处理程序。我该怎么做?我正在使用C 语言并使用Linux系统。
解决方案 1:
正如其他人已经说过的,要处理Control
+ D
,就需要处理“文件结束”。
Control
+D
是用户和您视为 stdin 的伪文件之间的一种通信。它并不特指“文件结束”,而是更一般地指“刷新我迄今为止输入的输入”。刷新意味着read()
程序中对 stdin 的任何调用都会返回自上次刷新以来输入的长度。如果行非空,则输入将可供程序使用,尽管用户尚未输入“return”。如果行是空的,则read()
返回零,这被解释为“文件结束”。
因此,当使用Control
+D
来结束程序时,它仅在行首起作用,或者如果您执行两次(第一次刷新,第二次read()
返回零)。
尝试一下:
$ cat
foo
(type Control-D once)
foofoo (read has returned "foo")
(type Control-D again)
$
解决方案 2:
Ctrl
+D
不是信号,而是 EOF(文件结束符)。它关闭 stdin 管道。如果 read(STDIN) 返回 0,则表示 stdin 已关闭,这意味着+被按下(假设管道另一端有键盘)。Ctrl
`D`
解决方案 3:
一个简单的例子:
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <signal.h>
void sig_hnd(int sig){ (void)sig; printf("(VINTR)"); }
int main(){
setvbuf(stdout,NULL,_IONBF,0);
struct termios old_termios, new_termios;
tcgetattr(0,&old_termios);
signal( SIGINT, sig_hnd );
new_termios = old_termios;
new_termios.c_cc[VEOF] = 3; // ^C
new_termios.c_cc[VINTR] = 4; // ^D
tcsetattr(0,TCSANOW,&new_termios);
char line[256]; int len;
do{
len=read(0,line,256); line[len]=' ';
if( len <0 ) printf("(len: %i)",len);
if( len==0 ) printf("(VEOF)");
if( len >0 ){
if( line[len-1] == 10 ) printf("(line:'%.*s')
",len-1,line);
if( line[len-1] != 10 ) printf("(partial line:'%s')",line);
}
}while( line[0] != 'q' );
tcsetattr(0,TCSANOW,&old_termios);
}
该程序将 VEOF 字符(从 Ctrl-D)更改为 Ctrl-C,将 VINTR 字符(从 Ctrl-C)更改为 Ctrl-D。如果您按下 Ctrl-D,则终端驱动程序将向程序的信号处理程序发送 SIGINT。
注意:按下 VINTR 将清除终端输入缓冲区,因此您无法读取按下 VINTR 键之前行中输入的字符。
解决方案 4:
无需处理信号。
您需要确保终端标志上没有设置 ISIG,仅此而已。
下面是使用 select 避免 stdin 阻塞的完整示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <sys/select.h>
#define STDIN_FILENO 0
struct termios org_opts;
/** Select to check if stdin has pending input */
int pending_input(void) {
struct timeval tv;
fd_set fds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0
select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &fds);
}
/** Input terminal mode; save old, setup new */
void setup_terminal(void) {
struct termios new_opts;
tcgetattr(STDIN_FILENO, &org_opts);
memcpy(&new_opts, &org_opts, sizeof(new_opts));
new_opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOKE | ISIG | ICRNL);
tcsetattr(STDIN_FILENO, TCSANOW, &new_opts);
}
/** Shutdown terminal mode */
void reset_terminal(void) {
tcsetattr(STDIN_FILENO, TCSANOW, &org_opts);
}
/** Return next input or -1 if none */
int next_input(void) {
if (!pending_input())
return -1;
int rtn = fgetc(stdin);
printf("Found: %d
", rtn);
return(rtn);
}
int main()
{
setup_terminal();
printf("Press Q to quit...
");
for (;;) {
int key = next_input();
if (key != -1) {
if ((key == 113) || (key == 81)) {
printf("
Normal exit
");
break;
}
}
}
reset_terminal();
return 0;
}
输出:
doug-2:rust-sys-sterm doug$ cc junk.c
doug-2:rust-sys-sterm doug$ ./a.out
Press Q to quit...
Found: 4
Found: 3
Found: 27
Found: 26
Found: 113
Normal exit
注意:3 是控制 C,4 是控制 D;26 是控制 z。113 是“q”。请参阅: http: //en.wikipedia.org/wiki/ASCII#ASCII_control_characters以查看完整表格。
解决方案 5:
据我所知,Ctrl
+D
被系统翻译为标准输入的结束,因此您的应用程序不会收到任何信号。
Ctrl
我认为拦截+的唯一方法D
是直接使用系统 API(如访问 tty)
解决方案 6:
您可以使用 poll() 并观察 fd #1 上的 POLLHUP,因为 TTY 层将 ^D 转换为 EOF。
解决方案 7:
Ctrl
ascci 表中的+D
值为 4,并且是不可打印字符。
因此,您可以使用以下代码在终端中捕获它。当 getline 函数 get Ctrl
+时D
,会发生错误,返回值为 -1。您可以对返回值设置条件。
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *buf = malloc(sizeof(char) * 500);
size_t size = 500;
int nb = getline(&buf, &size, stdin);
if (nb == -1)
printf("CTRL + D captured
");
free(buf);
return (0);
}
解决方案 8:
feof
您可以使用如下方法检查 stdin 是否不存在:
if (feof(stdin))
{
// some code
exit(0);
}
请参阅此处了解更多详情/
解决方案 9:
根据手册页,getline()
如果读取行失败(包括文件结尾情况),将返回 -1。如果发生错误,errno
将设置为指示原因。
这意味着:
当
getline()
遇到失败时,它将返回 -1 并errno
使用错误代码的值设置全局变量getline()
读取时CTRL+D
它将返回 -1 但不会设置errno
全局变量。
EINVAL
和是 可以设置ENOMEM
的两个可能的错误值。errno
`getline()`
因此,您可以以这样的方式构造代码,以测试返回的 -1 值是否getline()
是文件结束条件或如下错误的结果:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void)
{
char *buffer = NULL;
size_t bufsize = 0;
ssize_t characters;
/* initialize errno to 0 (this value will be changed if getline()
* encounters an error
*/
errno = 0;
characters = getline(&buffer, &bufsize, stdin);
if (characters == -1 && errno == 0)
{
printf("You entered CTRL+D
");
}
free(buffer);
return (0);
}
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件