"signal" --- 비동기 이벤트에 대한 처리기 설정
*********************************************

======================================================================

이 모듈은 파이썬에서 시그널 처리기를 사용하는 메커니즘을 제공합니다.


일반 규칙
=========

"signal.signal()" 함수는 시그널이 수신될 때 실행될 사용자 정의 처리기
를 정의하도록 합니다. 소수의 기본 처리기가 설치됩니다: "SIGPIPE"는 무
시되고 (그래서 파이프와 소켓에 대한 쓰기 에러는 일반 파이썬 예외로 보
고될 수 있습니다) "SIGINT"는 부모 프로세스가 변경하지 않았다면
"KeyboardInterrupt" 예외로 번역됩니다.

일단 설정되면, 특정 시그널에 대한 처리기는 명시적으로 재설정 될 때까지
(파이썬은 하부 구현과 관계없이 BSD 스타일 인터페이스를 흉내 냅니다) 설
치된 상태로 유지됩니다. "SIGCHLD"에 대한 처리기는 예외인데, 하부 구현
을 따릅니다.


파이썬 시그널 처리기의 실행
---------------------------

파이썬 시그널 처리기는 저수준 (C) 시그널 처리기 내에서 실행되지 않습니
다. 대신, 저수준 시그널 처리기는 *가상 기계*에게 나중에 (예를 들어 다
음 *바이트 코드* 명령에서) 해당 파이썬 시그널 처리기를 실행하도록 지시
하는 플래그를 설정합니다. 결과는 다음과 같습니다:

* C 코드에서의 유효하지 않은 연산으로 인해 발생하는 "SIGFPE"나
  "SIGSEGV"와 같은 동기 에러를 잡는 것은 그리 의미가 없습니다. 파이썬
  은 시그널 처리기에서 C 코드로 돌아오는데, 같은 시그널을 다시 발생시
  켜서, 파이썬이 멈출 것입니다. 파이썬 3.3부터는, "faulthandler" 모듈
  을 사용하여 동기 에러를 보고할 수 있습니다.

* C로만 구현된 오래 실행되는 계산(가령 커다란 텍스트 본문에 대한 정규
  식 일치)은 수신된 시그널에 상관없이 임의의 시간 동안 중단없이 실행될
  수 있습니다. 계산이 끝나면 파이썬 시그널 처리기가 호출됩니다.


시그널과 스레드
---------------

Python signal handlers are always executed in the main Python thread,
even if the signal was received in another thread.  This means that
signals can't be used as a means of inter-thread communication.  You
can use the synchronization primitives from the "threading" module
instead.

Besides, only the main thread is allowed to set a new signal handler.


모듈 내용
=========

버전 3.5에서 변경: 이하에 열거된 시그널 (SIG*), 처리기 ("SIG_DFL",
"SIG_IGN") 및 sigmask ("SIG_BLOCK", "SIG_UNBLOCK", "SIG_SETMASK") 관련
상수는 "열거형"으로 바뀌었습니다. "getsignal()", "pthread_sigmask()",
"sigpending()" 및 "sigwait()" 함수는 사람이 읽을 수 있는 "열거형"을 반
환합니다.

"signal" 모듈에 정의된 변수는 다음과 같습니다:

signal.SIG_DFL

   이것은 두 가지 표준 시그널 처리 옵션 중 하나입니다; 단순히 시그널의
   기본 기능을 수행합니다. 예를 들어, 대부분의 시스템에서 "SIGQUIT"의
   기본 동작은 코어를 덤프하고 종료하는 것이지만, "SIGCHLD"의 기본 동
   작은 단순히 무시하는 것입니다.

signal.SIG_IGN

   이것은 주어진 시그널을 무시하는 또 다른 표준 시그널 처리기입니다.

signal.SIGABRT

   *abort(3)*로 부터의 중단 시그널.

signal.SIGALRM

   *alarm(2)*로 부터의 타이머 시그널.

   가용성: 유닉스.

signal.SIGBREAK

   키보드 인터럽트 (CTRL + BREAK).

   가용성: 윈도우.

signal.SIGBUS

   버스 에러 (메모리 액세스 불량).

   가용성: 유닉스.

signal.SIGCHLD

   자식 프로세스가 중지되었거나 종료되었습니다.

   가용성: 유닉스.

signal.SIGCLD

   "SIGCHLD"에 대한 별칭.

signal.SIGCONT

   현재 중지되었으면 프로세스를 재개합니다.

   가용성: 유닉스.

signal.SIGFPE

   부동 소수점 예외. 예를 들어, 0으로 나누기.

   더 보기: 나누기나 모듈로 연산의 두 번째 인자가 0이면 "ZeroDivisionError"가
         발생합니다.

signal.SIGHUP

   제어 터미널이 끊어졌거나 제어 프로세스가 죽었습니다.

   가용성: 유닉스.

signal.SIGILL

   잘못된 명령어.

signal.SIGINT

   키보드 인터럽트 (CTRL + C).

   기본 액션은 "KeyboardInterrupt"를 발생시키는 것입니다.

signal.SIGKILL

   킬 시그널.

   잡거나, 차단하거나, 무시할 수 없습니다.

   가용성: 유닉스.

signal.SIGPIPE

   끊어진 파이프: 판독기가 없는 파이프에 쓰기.

   기본 동작은 시그널을 무시하는 것입니다.

   가용성: 유닉스.

signal.SIGSEGV

   세그먼테이션 오류: 유효하지 않은 메모리 참조.

signal.SIGTERM

   종료 시그널.

signal.SIGUSR1

   사용자 정의 시그널 1.

   가용성: 유닉스.

signal.SIGUSR2

   사용자 정의 시그널 2.

   가용성: 유닉스.

signal.SIGWINCH

   창 크기 조정 시그널.

   가용성: 유닉스.

SIG*

   모든 시그널 번호는 기호적으로 정의됩니다. 예를 들어, 행업(hangup)
   시그널은 "signal.SIGHUP"으로 정의됩니다; 변수 이름은 "<signal.h>"에
   있는 C 프로그램에서 사용되는 이름과 동일합니다. '"signal()"'에 대한
   유닉스 매뉴얼 페이지는 존재하는 시그널을 나열합니다 (일부 시스템에
   서는 *signal(2)*이고, 다른 시스템에서는 *signal(7)*입니다). 모든 시
   스템이 같은 시그널 이름 집합을 정의하는 것은 아님에 유의하십시오;
   시스템에서 정의한 이름만 이 모듈에서 정의합니다.

signal.CTRL_C_EVENT

   "Ctrl+C" 키 입력 이벤트에 해당하는 시그널. 이 시그널은 "os.kill()"
   에서만 사용할 수 있습니다.

   가용성: 윈도우.

   버전 3.2에 추가.

signal.CTRL_BREAK_EVENT

   "Ctrl+Break" 키 입력 이벤트에 해당하는 시그널. 이 시그널은
   "os.kill()"에서만 사용할 수 있습니다.

   가용성: 윈도우.

   버전 3.2에 추가.

signal.NSIG

   가장 높은 시그널 번호보다 하나 큰 값.

signal.ITIMER_REAL

   간격 타이머(interval timer)를 실시간으로 감소시키고, 만료 시
   "SIGALRM"을 전달합니다.

signal.ITIMER_VIRTUAL

   프로세스가 실행 중일 때만 간격 타이머(interval timer)를 감소시키고,
   만료 시 SIGVTALRM을 전달합니다.

signal.ITIMER_PROF

   프로세스가 실행될 때와 시스템이 프로세스를 대신하여 실행될 때 간격
   타이머(interval timer)를 감소시킵니다. ITIMER_VIRTUAL과 함께 사용되
   어, 이 타이머는 일반적으로 사용자와 커널 공간에서 응용 프로그램이
   소비한 시간을 프로파일링하는 데 사용됩니다. 만료 시 SIGPROF를 전달
   합니다.

signal.SIG_BLOCK

   "pthread_sigmask()"의 *how* 매개 변수에 가능한 값으로 시그널이 차단
   됨을 나타냅니다.

   버전 3.3에 추가.

signal.SIG_UNBLOCK

   "pthread_sigmask()"의 *how* 매개 변수에 가능한 값으로 시그널이 차단
   해제됨을 나타냅니다.

   버전 3.3에 추가.

signal.SIG_SETMASK

   "pthread_sigmask()"의 *how* 매개 변수에 가능한 값으로 시그널 마스크
   가 교체됨을 나타냅니다.

   버전 3.3에 추가.

"signal" 모듈은 하나의 예외를 정의합니다:

exception signal.ItimerError

   하부 "setitimer()"나 "getitimer()" 구현으로부터의 에러를 알리기 위
   해 발생합니다. 유효하지 않은 간격 타이머나 음의 시간이
   "setitimer()"에 전달되면 이 에러가 예상됩니다. 이 에러는 "OSError"
   의 서브 형입니다.

   버전 3.3에 추가: 이 에러는 "IOError"의 서브 형이었습니다, 이제는
   "OSError"의 별칭입니다.

"signal" 모듈은 다음 함수를 정의합니다:

signal.alarm(time)

   *time*이 0이 아니면, 이 함수는 "SIGALRM" 시그널이 *time* 초 내에 프
   로세스로 전송되도록 요청합니다. 이전에 예약된 알람은 취소됩니다 (임
   의의 시간에 오직 하나의 알람만 예약될 수 있습니다). 반환된 값은 이
   전에 설정된 알람이 전달되기까지 남은 초(seconds)입니다. *time*이 0
   이면, 알람이 예약되지 않고, 예약된 알람이 취소됩니다. 반환 값이 0이
   면, 현재 예약된 알람이 없습니다.

   가용성: 유닉스. 자세한 내용은 매뉴얼 페이지 *alarm(2)*를 참조하십시
   오.

signal.getsignal(signalnum)

   시그널 *signalnum*에 대한 현재 시그널 처리기를 반환합니다. 반환된
   값은 콜러블 파이썬 객체이거나, 특수 값 "signal.SIG_IGN",
   "signal.SIG_DFL" 중 하나이거나 "None"일 수 있습니다. 여기서
   "signal.SIG_IGN"은 시그널이 이전에 무시되었음을 의미하고,
   "signal.SIG_DFL"은 시그널을 처리하는 기본 방법이 이전에 사용 중임을
   의미하고, "None"은 이전 시그널 처리기가 파이썬에서 설치되지 않았음
   을 의미합니다.

signal.strsignal(signalnum)

   시그널 *signalnum*의 시스템 설명을 반환합니다, 가령 "Interrupt",
   "Segmentation fault", 등. 시그널이 인식되지 않으면 "None"을 반환합
   니다.

   버전 3.8에 추가.

signal.valid_signals()

   이 플랫폼에서 유효한 시그널 번호 집합을 반환합니다. 일부 시그널이
   시스템에서 내부 용으로 예약되었으면 "range(1, NSIG)"보다 작을 수 있
   습니다.

   버전 3.8에 추가.

signal.pause()

   시그널이 수신될 때까지 프로세스를 휴면 상태로 만듭니다; 그런 다음
   적절한 처리기가 호출됩니다. 아무것도 반환하지 않습니다.

   가용성: 유닉스. 자세한 내용은 매뉴얼 페이지 *signal(2)*를 참조하십
   시오.

   "sigwait()", "sigwaitinfo()", "sigtimedwait()" 및 "sigpending()"도
   참조하십시오.

signal.raise_signal(signum)

   호출하는 프로세스에 시그널을 보냅니다. 아무것도 반환하지 않습니다.

   버전 3.8에 추가.

signal.pthread_kill(thread_id, signalnum)

   Send the signal *signalnum* to the thread *thread_id*, another
   thread in the same process as the caller.  The target thread can be
   executing any code (Python or not).  However, if the target thread
   is executing the Python interpreter, the Python signal handlers
   will be executed by the main thread.  Therefore, the only point of
   sending a signal to a particular Python thread would be to force a
   running system call to fail with "InterruptedError".

   *thread_id*에 적합한 값을 얻으려면 "threading.get_ident()" 나
   "threading.Thread" 객체의 "ident" 어트리뷰트를 사용하십시오.

   *signalnum*이 0이면, 시그널이 전송되지 않지만, 여전히 에러 검사가
   수행됩니다; 대상 스레드가 여전히 실행 중인지 확인하는 데 사용할 수
   있습니다.

   인자 "thread_id", "signalnum"으로 감사 이벤트 "signal.pthread_kill"
   을 발생시킵니다.

   가용성: 유닉스. 자세한 내용은 매뉴얼 페이지 *pthread_kill(3)*을 참
   조하십시오.

   "os.kill()"도 참조하십시오.

   버전 3.3에 추가.

signal.pthread_sigmask(how, mask)

   호출하는 스레드의 시그널 마스크를 가져오거나 변경하거나 가져오면서
   변경합니다. 시그널 마스크는 호출자에게 현재 배달이 차단된 시그널 집
   합입니다. 이전 시그널 마스크를 시그널 집합으로 반환합니다.

   호출의 동작은 다음과 같이 *how* 값에 따라 다릅니다.

   * "SIG_BLOCK": 차단된 시그널 집합은 현재 집합과 *mask* 인자의 합집
     합입니다.

   * "SIG_UNBLOCK": *mask*에 있는 시그널이 차단된 시그널의 현재 집합에
     서 제거됩니다. 차단되지 않은 시그널을 차단 해제하려고 시도할 수
     있습니다.

   * "SIG_SETMASK": 차단된 시그널 집합이 *mask* 인자로 설정됩니다.

   *mask*는 시그널 번호 집합입니다 (예를 들어 {"signal.SIGINT",
   "signal.SIGTERM"}). 모든 시그널을 포함한 전체 마스크를 얻으려면
   "valid_signals()"를 사용하십시오.

   예를 들어, "signal.pthread_sigmask(signal.SIG_BLOCK, [])"은 호출하
   는 스레드의 시그널 마스크를 읽습니다.

   "SIGKILL"과 "SIGSTOP"은 차단할 수 없습니다.

   가용성: 유닉스. 자세한 내용은 매뉴얼 페이지 *sigprocmask(3)*과
   *pthread_sigmask(3)*을 참조하십시오.

   "pause()", "sigpending()" 및 "sigwait()"도 참조하십시오.

   버전 3.3에 추가.

signal.setitimer(which, seconds, interval=0.0)

   *seconds*("alarm()"과 달리 float가 허용됩니다) 이후에 그리고
   (*interval*이 0이 아니면) 그 후로 *interval* 초마다 발사(fire)하도
   록 *which*로 지정된 간격 타이머("signal.ITIMER_REAL",
   "signal.ITIMER_VIRTUAL" 또는 "signal.ITIMER_PROF" 중 하나)를 설정합
   니다. *which*로 지정된 간격 타이머는 *seconds*를 0으로 설정하여 지
   울 수 있습니다.

   간격 타이머가 발사(fire)하면, 시그널이 프로세스로 전송됩니다. 전송
   된 시그널은 사용 중인 타이머에 따라 다릅니다; "signal.ITIMER_REAL"
   은 "SIGALRM"을, "signal.ITIMER_VIRTUAL"은 "SIGVTALRM"을,
   "signal.ITIMER_PROF"는 "SIGPROF"를 전달합니다.

   이전 값은 튜플로 반환됩니다: (지연, 간격).

   유효하지 않은 간격 타이머를 전달하려고 하면 "ItimerError"가 발생합
   니다.

   가용성: 유닉스.

signal.getitimer(which)

   *which*로 지정된 주어진 간격 타이머의 현재 값을 반환합니다.

   가용성: 유닉스.

signal.set_wakeup_fd(fd, *, warn_on_full_buffer=True)

   웨이크업 파일 기술자를 *fd*로 설정합니다. 시그널이 수신되면 시그널
   번호는 단일 바이트로 fd에 기록됩니다. 라이브러리에서 poll이나
   select 호출을 깨워서, 시그널을 완전히 처리하는 데 사용될 수 있습니
   다.

   이전 웨이크업 fd가 반환됩니다 (또는 파일 기술자 웨이크업이 활성화되
   지 않았으면 -1). *fd*가 -1이면, 파일 기술자 웨이크업이 비활성화됩니
   다. -1이 아니면, *fd*는 비 블로킹이어야 합니다. poll이나 select를
   다시 호출하기 전에 *fd*에서 바이트를 제거하는 것은 라이브러리의 책
   임입니다.

   When threads are enabled, this function can only be called from the
   main thread; attempting to call it from other threads will cause a
   "ValueError" exception to be raised.

   이 함수를 사용하는 일반적인 두 가지 방법이 있습니다. 두 방법 모두,
   시그널이 도착할 때 깨어나기 위해 fd를 사용하지만, *어떤* 시그널이나
   시그널들이 도착했는지 판단하는 방법이 다릅니다.

   첫 번째 방법에서는, fd의 버퍼에서 데이터를 읽고, 바이트 값이 시그널
   번호를 제공합니다. 이것은 간단합니다만, 드물게 문제가 될 수 있습니
   다: 일반적으로 fd에는 제한된 버퍼 공간이 있으며, 너무 많은 시그널이
   너무 빨리 도착하면, 버퍼가 가득 차고, 일부 시그널이 손실될 수 있습
   니다. 이 방법을 사용하면, 시그널이 손실될 때 최소한 stderr에 경고가
   인쇄되도록 "warn_on_full_buffer=True"를 설정해야 합니다.

   두 번째 방법에서는, 오직 웨이크업만을 위해 웨이크업 fd를 사용하고,
   실제 바이트 값은 무시합니다. 이 경우, 우리가 신경 쓰는 것은 fd의 버
   퍼가 비어 있는지 비어 있지 않은지 입니다; 가득 찬 버퍼는 전혀 문제
   를 가리키지 않습니다. 이 방법을 사용하면, 사용자가 가짜 경고 메시지
   로 혼동되지 않도록 "warn_on_full_buffer=False"를 설정해야 합니다.

   버전 3.5에서 변경: 윈도우에서, 이 함수는 이제 소켓 핸들도 지원합니
   다.

   버전 3.7에서 변경: "warn_on_full_buffer" 매개 변수를 추가했습니다.

signal.siginterrupt(signalnum, flag)

   시스템 호출 재시작 동작을 변경합니다: *flag*가 "False"이면, 시그널
   *signalnum*에 의해 인터럽트 될 때 시스템 호출이 다시 시작되고, 그렇
   지 않으면 시스템 호출이 중단됩니다. 아무것도 반환하지 않습니다.

   가용성: 유닉스. 자세한 내용은 매뉴얼 페이지 *siginterrupt(3)*을 참
   조하십시오.

   "signal()"로 시그널 처리기를 설치하면 주어진 시그널에 대해 *flag*
   값을 참으로 "siginterrupt()"를 묵시적으로 호출하여 재시작 동작을 인
   터럽트 가능으로 재설정합니다.

signal.signal(signalnum, handler)

   시그널 *signalnum*의 처리기를 함수 *handler*로 설정합니다.
   *handler*는 두 개의 인자(아래를 참조하십시오)를  취하는 콜러블 파이
   썬 객체, 또는 특수 값 "signal.SIG_IGN"이나 "signal.SIG_DFL" 중 하나
   일 수 있습니다. 이전 시그널 처리기가 반환됩니다 (위의 "getsignal()"
   설명을 참조하십시오). (자세한 내용은 유닉스 매뉴얼 페이지
   *signal(2)*를 참조하십시오.)

   When threads are enabled, this function can only be called from the
   main thread; attempting to call it from other threads will cause a
   "ValueError" exception to be raised.

   *handler*는 두 개의 인자로 호출됩니다: 시그널 번호와 현재 스택 프레
   임 ("None"이나 프레임 객체; 프레임 객체에 대한 설명은, 형 계층에 있
   는 설명을 참조하거나 "inspect" 모듈의 어트리뷰트 설명을 참조하십시
   오).

   윈도우에서, "signal()"은 "SIGABRT", "SIGFPE", "SIGILL", "SIGINT",
   "SIGSEGV", "SIGTERM" 또는 "SIGBREAK"로만 호출 할 수 있습니다. 다른
   경우에는 "ValueError"가 발생합니다. 모든 시스템이 같은 시그널 이름
   집합을 정의하는 것은 아님에 유의하십시오; 시그널 이름이 "SIG*" 모듈
   수준 상수로 정의되지 않으면 "AttributeError"가 발생합니다.

signal.sigpending()

   호출하는 스레드로 전달 계류 중인 시그널 집합을 검사합니다 (즉, 차단
   된 동안 발생한 시그널). 계류 중인 시그널 집합을 반환합니다.

   가용성: 유닉스. 자세한 내용은 매뉴얼 페이지 *sigpending(2)*를 참조
   하십시오.

   "pause()", "pthread_sigmask()" 및 "sigwait()"도 참조하십시오.

   버전 3.3에 추가.

signal.sigwait(sigset)

   시그널 집합 *sigset*에 지정된 시그널 중 하나가 전달될 때까지 호출하
   는 스레드의 실행을 일시 중단합니다. 이 함수는 시그널을 받아들이고 (
   계류 중인 시그널 목록에서 제거합니다), 시그널 번호를 반환합니다.

   가용성: 유닉스. 자세한 내용은 매뉴얼 페이지 *sigwait(3)*을 참조하십
   시오.

   "pause()", "pthread_sigmask()", "sigpending()", "sigwaitinfo()" 및
   "sigtimedwait()"도 참조하십시오.

   버전 3.3에 추가.

signal.sigwaitinfo(sigset)

   시그널 집합 *sigset*에 지정된 시그널 중 하나가 전달될 때까지 호출하
   는 스레드의 실행을 일시 중단합니다. 이 함수는 시그널을 받아들이고
   계류 중인 시그널 목록에서 제거합니다. *sigset*의 시그널 중 하나가
   이미 호출하는 스레드에 대해 계류 중이면, 함수는 해당 시그널에 대한
   정보와 함께 즉시 반환합니다. 전달된 시그널에 대해 시그널 처리기가
   호출되지 않습니다. 이 함수는 *sigset*에 없는 시그널에 의해 중단되면
   "InterruptedError"를 발생시킵니다.

   반환 값은 "siginfo_t" 구조체에 포함된 데이터, 즉 "si_signo",
   "si_code", "si_errno", "si_pid", "si_uid", "si_status", "si_band"를
   표현하는 객체입니다.

   가용성: 유닉스. 자세한 내용은 매뉴얼 페이지 *sigwaitinfo(2)*를 참조
   하십시오.

   "pause()", "sigwait()" 및 "sigtimedwait()"도 참조하십시오.

   버전 3.3에 추가.

   버전 3.5에서 변경: 이 함수는 이제 *sigset*에 없는 시그널에 의해 중
   단되고 시그널 처리기가 예외를 발생시키지 않으면 재시도됩니다 (이유
   는 **PEP 475**를 참조하십시오).

signal.sigtimedwait(sigset, timeout)

   "sigwaitinfo()"와 유사하지만, 시간제한을 지정하는 추가 *timeout* 인
   자를 취합니다. *timeout*이 "0"으로 지정되면, 폴링이 수행됩니다. 시
   간제한 초과가 발생하면 "None"을 반환합니다.

   가용성: 유닉스. 자세한 내용은 매뉴얼 페이지 *sigtimedwait(2)*를 참
   조하십시오.

   "pause()", "sigwait()" 및 "sigwaitinfo()"도 참조하십시오.

   버전 3.3에 추가.

   버전 3.5에서 변경: 이 함수는 이제 *sigset*에 없는 시그널에 의해 중
   단되고 시그널 처리기가 예외를 발생시키지 않으면 다시 계산된
   *timeout*으로 재시도됩니다 (이유는 **PEP 475**를 참조하십시오).


예
==

다음은 최소한의 예제 프로그램입니다. "alarm()" 함수를 사용하여 파일을
여는 데 대기하는 시간을 제한합니다; 이것은 파일이 켜져 있지 않을 수 있
는 직렬 장치를 위한 파일일 때 유용하며, 일반적으로 "os.open()"이 무기
한 정지됩니다. 해결책은 파일을 열기 전에 5초 알람을 설정하는 것입니다;
작업이 너무 오래 걸리면, 알람 시그널이 전송되고, 처리기가 예외를 발생
시킵니다.

   import signal, os

   def handler(signum, frame):
       print('Signal handler called with signal', signum)
       raise OSError("Couldn't open device!")

   # Set the signal handler and a 5-second alarm
   signal.signal(signal.SIGALRM, handler)
   signal.alarm(5)

   # This open() may hang indefinitely
   fd = os.open('/dev/ttyS0', os.O_RDWR)

   signal.alarm(0)          # Disable the alarm


SIGPIPE에 대한 참고 사항
========================

프로그램의 출력을 *head(1)*와 같은 도구로 파이핑 하면 표준 출력의 수신
기가 일찍 닫힐 때 여러분의 프로세스로 "SIGPIPE" 시그널이 전송됩니다.
이것은 "BrokenPipeError: [Errno 32] Broken pipe"와 같은 예외를 일으킵
니다. 이 경우를 처리하려면, 다음과 같이 이 예외를 포착하도록 진입점을
감싸십시오:

   import os
   import sys

   def main():
       try:
           # simulate large output (your code replaces this loop)
           for x in range(10000):
               print("y")
           # flush output here to force SIGPIPE to be triggered
           # while inside this try block.
           sys.stdout.flush()
       except BrokenPipeError:
           # Python flushes standard streams on exit; redirect remaining output
           # to devnull to avoid another BrokenPipeError at shutdown
           devnull = os.open(os.devnull, os.O_WRONLY)
           os.dup2(devnull, sys.stdout.fileno())
           sys.exit(1)  # Python exits with error code 1 on EPIPE

   if __name__ == '__main__':
       main()

"BrokenPipeError"를 피하고자 "SIGPIPE"의 배치를 "SIG_DFL"로 설정하지
마십시오. 그렇게 하면 프로그램이 여전히 쓰고 있는 동안 소켓 연결이 중
단될 때마다 프로그램이 예기치 않게 종료되도록 합니다.
