언제 shutdown()를 써야 하는가?

Network/Network 2011. 11. 23. 17:38

 언제 shutdown()를 써야 하는가?

Michael Hunter (mphunter@qnx.com)로부터:

shutdown()은 여러분은 TCP를 사용하여 서버로 요청 하는일을 언제 끝냈는지 알아 내는데 유용하다. 전형적인 사용예는 서버 로 요청이 전달되고 나후에 shutdown()이 이루어 졌을 경우에 유용하다. 서버는 여러분의 호출을 EOF일때까지 받는다. 즉 이것 은 서버가 여러분의 완전한 요청을 받았다는 것을 의미한다. 그리고 나서 소켓에서의 read는 블록된다. 서버는 요청을 처리하고 필요한 데이터를 여러분에게 보내고 소켓을 닫게 된다. 여러분이 필요한 모든 내용을 소켓에서 읽었다면 마지막에 EOF를 읽게 될 것이다. 이것은 TTCP(TCP for Transactions)가 보다 나은 트랜잭션 처리를 위한 도구 라는 것을 보여준다.

S.Degtyarev (deg@sunsr.inp.nsk.su)는 이것에 관한 상세한 메시지를 내게 보내 주었다. 그는 하나는 "reader"이고 다른 하나는 "write" 프로세스인 클라이언트 프로세스의 동기화를 도와주는 shutdown()에 대한 실제 예제까 들었다. 여기 그것의 일부를 여기 싣는다.

소켓은 데이터 전달과 클라이언트/서버 트랜잭션에 사용된다는 점에서 파이프와 매우 비슷하다 그러나 파이프와 다른 점은 양 방향 성이라는 것이다. 소켓을 사용하는 프로그램은 자주 fork()하고 각 프로세스는 소켓 드스크립터를 상속받는다. 파이프에 기 본을 둔 프로그램은 데이터 상실이나 deadlock을 피하는 단방향성의 데이터 스트림으로 pipe line을 만들기 위해 사용되지 않는 모든 끝은 닫도록 엄격히 권고되고 있다. 그러나 소켓의 경우에는 한쪽은 쓰기만 하고 한쪽은 받기만 하는 것은 허용되지 않기 때문에 여러분들은 그 순서에 유념해야 할 필요가 있다.

일반적으로 close()와 shutdown()의 차이점은: close()는 프로세스에 대해 소켓 ID를 닫지만 만약 다른 프로세스가 소켓 ID를 공유하고 있다면 연결은 여전히 열려 있게 된다. 그 연결은 읽기,쓰기를 위해 유지 되며, 어떤때, 이것은 매우! 중요하다. shut down()은 그 소켓 ID를 공유하고 있는 모든 프로세스에 대해 연결을 끊어버린다. 커널 소켓 버퍼가 꽉 차이 있으면 읽기를 시도 하는 프로세스는 EOF를 발견하게 되고, 쓰기를 시도하는 프로세스는 SIGPIPE를 받게 된다. 게다가 shutdown()은 그 연결을 어떻 게 끊을지를 나타내는 두 번째 파라메터를 가지고 있는데, 0은 이후의 읽기를 못하게하고, 1은 쓰기를, 2는 양쪽 모두를 못하게 한다.

이 쉬운 예제는 단순한 클라이언트 프로세스를 자른 것이다. 연결을 설립한 후에 서버는 fork한다. 그리고 나서 child는 EOF 를 받거나 부모프로세스가 서버로부터 응답을 받을 때까지 키 입력을 서버에게 전송한다.

/*
 * 예제 클라이언트 쪼가리..
 * 변수선언과 에러 핸들링은 제외 됐음
 */

s=connect(...);

if( fork() ){     /* 자식은 그 stdin을 소켓으로 복사한다 */
   while( gets(buffer) >0)
   write(s,buf,strlen(buffer));

   close(s);
   exit(0);
   }
else {            /* 부모가 응답을 받는다 */
   while( (l=read(s,buffer,sizeof(buffer)){
      do_something(l,buffer);

   /* 서버가 연결을 끊는다 */
   /* ATTENTION: deadlock here */
   wait(0);       /* 자식이 나갈때까지 기다림 */
   exit(0);
   }

무엇을 기대할 수 있는가? 자식프로세스는 stdin으로부터 EOF를 받으면 소켓을 닫고 빠져 나간다. 서버는 EOF를 받으면 연결 을 끊고 빠져 나간다. 부모 프로세스는 EOF를 받으면 wai()을 호출하고 빠져 나간다. 이것 대신 우린 뭘 할 수 있을까? 비록 부 모 프로세스가 쓰기를 하지 않을지 모르지만 부모 프로세스에 있는 소켓 인스턴스는 읽기와 쓰기를 위해 여전히 열려 있다. 서버 는 EOF를 발견하지 못한다. 그리고 영원히 클라이언트로부터의 데이터를 기다린다. 그리고 서버도 죽~. (여기서 deadlock이 발생 된다.)

여러분은 클라이언트 프로그램을 다음과 같이 바꿔야 한다.

if( fork() ) { /* 자식 */
   while( gets(buffer) )
      write(s,buffer,strlen(buffer));

   shutdown(s,1); /* 쓰기를 위해 연결을 끊는다
      서버는 EOF를 받게 된다. Note: 소켓으로부터의 읽기는 여전히 허용된다.
      서버는 EOF를 받은 후에 몇 데이터를 보낼 것이다. */
   exit(0);
   }

나는 이 다듬어 지지 않은 예제가 여러분들이 가지고 있는 클라이언트/서버의 동기화의 문제를 설명해 줄 수 있기를 바란다. 일반적으로 여러분들이 모든 프로세스의 특정 소켓 인스턴스에서 기억하고 있어야 할 것이 있는데, 만약 여러분이 하나의 프로세 스 안에서 연결을 끊기 위해 close()또는 shutdown()을 사용하길 바란다면, 그들 모두를 공유하고 있다가 한 번에 닫아라.

출처 -  http://forum.falinux.com/zbxe/?document_srl=448212#26

'Network > Network' 카테고리의 다른 글

gethostbyname() 도메인 이름으로 hostent 정보를 구함  (0) 2011.12.01
inet_addr, inet_aton  (1) 2011.12.01
소켓 함수 모음  (0) 2011.11.11
struct sockaddr, sockaddr_in, sockaddr_un  (0) 2011.11.07
멀티캐스트 (Multicast)  (0) 2011.11.02
: