SIGPIPE handle

c4fiber·2023년 12월 22일
0

SW사관학교 정글7기

목록 보기
34/49

추가내용


원인은 HTTP response header에 있었다.
HTTP/1.0 은 헤더의 대소문자를 구분하는데 나는 "Content-Length"에서 Length의 L을 소문자로 작성해서 발생한 문제였다.

클라이언트는 Content-Length에 대한 내용을 받지 못하고, 모종의 이유로 패킷이 나눠서 전송될 경우 파일의 끝인줄 알고 연결을 끊어버렸던 것이였다....

발생 증상


다음과 같이 데이터를 마저 쓰지 못한채로 socket이 닫혀서 프로그램이 종료되는 현상이 발생했다.

SIGPIPE error는 왜 발생하는가?


소켓 통신을 통해서 client에게 데이터를 전달하던 도중 client가 소켓을 닫아버리는 경우가 있다.

정확한 원인은 알수없지만 추측하기로는

  • 요청한 데이터가 이미 캐싱되어 보유하고 있음을 판단했을 때
  • 클라이언트가 다른 페이지로 이동해서 더 이상 데이터가 필요없을 때

이때 클라이언트는 소켓을 닫아버려도 서버는 데이터를 connfd를 통해 데이터를 계속 보내려고 한다.
이 순간 서버는 SIGPIPE(Connection reset by peer, broken pipe)에 직면하게 된다.

어떻게 처리 할 것인가?


몇가지 방법을 시도해보았다.

1. SIGPIPE 에러 자체를 무시해버린다.

  • signal(SIGPIPE, SIG_IGN) 를 호출한다. (주로 main에서 이루어짐)

2. Socket을 생성할 때 SIGPIPE 에러를 무시하도록 설정한다.

  • setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int))

2번의 방법은 send()를 사용할 때 적용된다고 한다 (범용적이지 않아서 매번 적용되는지 알 수 없다, linux에서는 없을 수도 있음) 관련 stackoverflow 링크

따라서 2번의 경우는 MSG_NOSIGNAL 을 사용하는 방법으로 선회해야한다고 한다.

3. (추가) HTTP 206 을 통해 데이터를 나눠서 보낸다.

데이터를 잘라서 보내야 하는가? 라는 의문을 가지고 정보를 찾고 문제해결을 시도해보았다.

HTTP status code 206

https://developer.mozilla.org/ko/docs/Web/HTTP/Status/206

대용량 파일 전송이나, 비디오 스트리밍 등에 주로 사용된다.

큰 용량의 데이터를 한 번에 받기 힘든 사용자는 data의 일부분을 요구할 수 있다.
이 요청이 처리될 경우 server는 HTTP 206 response를 보낸다.

요청이 처리되는 순서

  1. 서버 측에서 전달받은 HTTP header의 Accept-Ranges: 를 통해 부분전송 가능여부를 확인한다.
    none 일경우 불가능, bytes 의 경우 byte 단위로 끊어서 전송할 수 있다는 뜻이다.

  2. 클라이언트는 헤더에 Range: start-end 를 추가한다. start ~ end까지의 bytes를 전달해달라는 뜻이다.

  3. 서버는 데이터를 전송할 때 Content-Range: start-end/total size 를 헤더에 추가한다.
    동시에 HTTP 206 Response를 전달한다.

나는 csapp.c 파일을 수정하지 말아야 한다는 나만의 원칙아래 1번의 방법을 선택했다.

profile
amazing idiot

0개의 댓글