[SIGPIPE]
프로세스가 읽기가 안되는 파이프에 쓰려고 한다면, 커널로 부터 SIGPIPE 신호를 받게 된다. 이것은 두개 이상의 프로세스가 파이프라인에 포함되어 있을 때 필수적이다.
참고로, 모든 시그널이 임의의 쓰레드로 전달되는 것은 아닙니다.
SIGFPE (부동 소수점 연산 오류), SIGSEGV (메모리 접근 오류) 등과 같이 명백하게 시그널을 발생시킨 쓰레드가 정해져 있는 경우는 해당 쓰레드에게 시그널이 전달됩니다. 이런 시그널을 synchronous signal 이라고 하는데, SIGPIPE도 이 범주에 들지 않을까 합니다.
클라이언트에서 소켓을 끊었다고 해서 서버에 SIGPIPE가 전달되는 것은 아닙니다. SIGPIPE는 상대방이 닫은 fd로 쓰기를 하려는 순간에 발생합니다.
파이프 닫기
pclose()함수는 스트림을 닫은 후 리눅스의 함수인 wait4()를 호출하여
자식 프로세스 파이프의 다른 쪽의 프로세스가 종료될 때까지 기다리게 한다.
이렇게 함으로써 pclose() 함수는 자식 프로세스에게 성공/실패 상태를
전달한다. 그 시간은 자식 프로세스가 종료되는 시점이다.
pclose()를 사용하지 않고 fclose()를 사용할 경우 좀피(zombie)프로세스가
생성된다.
#include<stdio.h>
int pclose(FILE *stream);
부서진 파이프의 처리
시그널(SIGPIPE)은 파이프가 "손상 됐다"는 것을 의미한다.
시그널은 리눅스 커널에 의해서 발생하는 비동기적(asynchronous)인 이벤트이다.
1. signal.h 파일을 포함한다.
2. 첫번째 파이프를 열기 전에 signal(SIGPIPE,SIG_IGN)을 호출한다. 이 호출은 리눅스 커널에게 만약 SIGPIPE 시그널이 발생하게 되면 무시하라고 말한다.
int main(it argc, char *argv) {
struct passwd *pw = 0; /* 비밀번호 정보 */
char cmd[256]; /* 명령 버퍼 */
FILE *p = 0; /* mailx 파이프 */
signal(SIGPIPE, SIG_IGN); /* SIGPIPE의 무시 */
이 함수는 SIGPIPE 시그널이 발생하게 되면 쓰기의 호출이 에러(EPIPE)를
반환 하거나 pclose() 함수가 에러를 반환하게 한다. 이것의 결과는
SIGPIPE가 발생하였을 때 프로그램 자체적으로 기본적인 동작을 수행하게
하는 것보다는 휠씬 좋은 일이다.
---------------------------------
> 제가 이번에 하는것은 IMB AIX 운영체제 하에서 돌아가는 파일전송 서버입니다.
>
> 문제는 서버가 파일을 전송하고 클라이언트가 파일을 전송받다가 클라이언트가
> 파일전송을 취소하고 중지하면 이상하게 서버도 같이 종료된다는 것입니다.
>
> 그래서 send에러시 에러메세지가 나오게되 해보았는데 역시 에러 메세지가
> 안나오고 바로 종료되더군요.
>
> 제가 생각하기에는 런타임 에러같은데 혹시 저와 같은 경험을 하신분은
> 없으신지....
>
> 참고로 쓰레드는 POSIX 쓰레드를 썻고 서버가 클라이언트의 접속요청을
> 기다리다가 접속될때 파일전송 쓰레드가 구동 되도록 만들었습니다.
>
> 아래부분이 문제의 send부분입니다. 리눅스에서는 아무문제가 발생하지
않았고요.
>
> if(send(client_socket, (const char *)send_buffer, sizeof(SEND_DATA), 0)
> == -1)
> {
> printf("send error 1-1 ");
> break;
> }
>
이상하네요.
리눅스라 할지라도 데이터를 받던 클라이언트 쪽에서 접속을 끊으면
서버쪽에 SIGPIPE이 뜨게 됩니다.
SIGPIPE에 대한 디폴트 핸들러는 프로세스를 종료시킵니다.
따라서 이 해법은 SIGPIPE을 시그널 핸들러로 마스크 (SIG_IGN) 시키던지 send()의 마지막 플래그를 0으로 주지 말고 SIGPIPE을 무시하는 플래그로 셋팅을 하면 됩니다.