programing

Control+D 신호를 캡처하는 방법

bestcode 2022. 8. 27. 09:36
반응형

Control+D 신호를 캡처하는 방법

프로그램에서 +D 신호를 캡처하여 신호 핸들러를 쓰고 싶습니다.내가 어떻게 그럴 수 있을까?저는 C에서 Linux 시스템을 사용하고 있습니다.

다른 사용자가 이미 말했듯이 D+를 처리하려면 "파일 끝"을 처리합니다.

Control+D는 사용자와 stdin으로 표시되는 의사 파일 간의 통신입니다.이는 구체적으로 "파일 끝"을 의미하는 것이 아니라 일반적으로 "지금까지 입력한 입력을 플러시"를 의미합니다.플러싱이란 어떤 것이든read()프로그램에서 stdin을 호출하면 마지막 플러시 이후 입력된 길이와 함께 반환됩니다.행이 비어 있지 않으면 사용자가 아직 "return"을 입력하지 않았더라도 프로그램에서 입력을 사용할 수 있습니다.행이 비어 있는 경우는,read()는 0으로 반환되며, 이는 "파일 끝"으로 해석됩니다.

따라서 +를 D사용하여 프로그램을 종료할 때는 행의 선두에서만 동작하거나 두 번(처음 플러시, 두 번째 플러시)하는 경우에만 동작합니다.read()0을 반환한다).

시험해 보세요:

$ cat
foo
   (type Control-D once)
foofoo (read has returned "foo")
   (type Control-D again)
$

+는 신호가 아니라 EOF(End-Of-File)입니다Ctrl.Dstdin 파이프를 닫습니다.읽기(STDIN)가 0을 반환하는 경우 stdin이 닫힘을 의미하며, 이는 +가 히트되었음을 의미합니다(D파이프의 다른 끝에 키보드가 있다고 가정).

미니멀리즘의 예:

#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]='\0';
    if( len <0 ) printf("(len: %i)",len);
    if( len==0 ) printf("(VEOF)");
    if( len >0 ){
      if( line[len-1] == 10 ) printf("(line:'%.*s')\n",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 키를 누르기 전에 행에 입력된 문자를 읽을 수 없습니다.

Ctrl + ascci 표의 값은 4이며 인쇄할 수 없는 문자입니다.
따라서 다음 코드를 사용하여 단말기에서 캡처할 수 있습니다.getline 함수의 get +에서 오류가 발생하고 값이 -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\n");
    free(buf);
    return (0);
}

신호를 처리할 필요가 없습니다.

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\n", rtn);
  return(rtn);
}

int main()
{
  setup_terminal();

  printf("Press Q to quit...\n");
  for (;;) {
    int key = next_input();
    if (key != -1) {
      if ((key == 113) || (key == 81)) {
        printf("\nNormal exit\n");
        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

NB. 3은 제어 C, 4는 제어 D, 26은 제어 z, 113은 'q'입니다.전체 표에 대해서는 http://en.wikipedia.org/wiki/ASCII#ASCII_control_characters 를 참조하십시오.

FD #1에서는 POLLHUP을 감시할 수 있습니다.TTY 레이어는 ^D를 EOF로 변환하기 때문입니다.

제가 D알기로는 +는 시스템에 의해 표준 입력의 끝으로 변환되어 앱에 아무런 신호도 전달되지 않습니다.

+D를 가로채는 유일한 방법은 시스템 API로 직접 작업하는 것이라고 생각합니다(예를 들어 tty 접근).

언급URL : https://stackoverflow.com/questions/1516122/how-to-capture-controld-signal

반응형