2011년7월13일_소켓의 송수신 버퍼 크기설정(소켓옵션), Signal(OS→App), SIGINT와 SIGALRM signal처리 예제




소켓의 버퍼크기 확인/설정



● 송수신 버퍼의 크기를 확인...get_buf.c

   1:  // get_buf.c
   2:  #include <stdio.h>
   3:  #include <stdlib.h>
   4:  #include <unistd.h>
   5:  #include <sys/types.h>
   6:  #include <sys/socket.h>
   7:   
   8:  void error_handling(char *message);
   9:   
  10:  int main()
  11:  {
  12:      int sock;
  13:      int snd_buf;
  14:      int rcv_buf;
  15:      int state;
  16:      socklen_t len;
  17:   
  18:      sock = socket(PF_INET, SOCK_STREAM, 0);
  19:   
  20:      len = sizeof(snd_buf);
  21:      state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &snd_buf, &len);
  22:   
  23:      if(-1 == state)
  24:      {
  25:          error_handling("getsockopt() error");
  26:      }
  27:   
  28:      len = sizeof(rcv_buf);
  29:      state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcv_buf, &len);
  30:   
  31:      if(-1 == state)
  32:      {
  33:          error_handling("getsockopt() error");
  34:      }
  35:      
  36:      printf("데이터 입력받기 위한 소켓의 버퍼 크기 : %d \n", rcv_buf);
  37:      printf("데이터 출력하기 위한 소켓의 버퍼 크기 : %d \n", snd_buf);
  38:   
  39:      return 0;
  40:  }
  41:   
  42:  void error_handling(char *message)
  43:  {
  44:      fputs(message, stderr);
  45:      fputc('\n', stderr);
  46:      exit(1);
  47:  }


<실행결과>

image


<소스분석>

//후에 추가

 

● 소켓의 버퍼크기를 설정한 뒤에 읽어와 확인...set_buf.c

   1:  // set_buf.c
   2:  #include <stdio.h>
   3:  #include <stdlib.h>
   4:  #include <unistd.h>
   5:  #include <sys/types.h>
   6:  #include <sys/socket.h>
   7:   
   8:  void error_handling(char *message);
   9:   
  10:  int main()
  11:  {
  12:      int sock;
  13:      int snd_buf = 500;
  14:      int rcv_buf = 1000;
  15:      int state;
  16:      socklen_t len;
  17:   
  18:      sock = socket(PF_INET, SOCK_STREAM, 0);
  19:      
  20:      //입출력 버퍼 크기 설정
  21:      state = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcv_buf, sizeof(rcv_buf));
  22:   
  23:      if(-1 == state)
  24:      {
  25:          error_handling("getsockopt() error");
  26:      }
  27:   
  28:      state = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &snd_buf, sizeof(snd_buf));
  29:   
  30:      if(-1 == state)
  31:      {
  32:          error_handling("getsockopt() error");
  33:      }
  34:   
  35:      //입출력 버퍼 크기 확인
  36:      len = sizeof(rcv_buf);
  37:      state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcv_buf, &len);
  38:   
  39:      if(-1 == state)
  40:      {
  41:          error_handling("getsockopt() error");
  42:      }
  43:   
  44:      len = sizeof(snd_buf);
  45:      state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &snd_buf, &len);
  46:   
  47:      if(-1 == state)
  48:      {
  49:          error_handling("getsockopt() error");
  50:      }
  51:      
  52:      printf("데이터 입력받기 위한 소켓의 버퍼 크기 : %d \n", rcv_buf);
  53:      printf("데이터 출력하기 위한 소켓의 버퍼 크기 : %d \n", snd_buf);
  54:   
  55:      return 0;
  56:  }
  57:   
  58:  void error_handling(char *message)
  59:  {
  60:      fputs(message, stderr);
  61:      fputc('\n', stderr);
  62:      exit(1);
  63:  }


<실행결과>

image



<소스분석>

● setsockopt( )의 원형

   1:  // 성공시 0, 실패시 -1을 리턴
   2:  // 소켓디스크립터, 프로토콜레벨, 변경할 옵션의 이름, 옵션값 저장버퍼, 버퍼크기 인수
   3:  int setsockopt(int socket, int level, int optName, const void *optVal, socklen_t optLen);

getsockopt( )와 똑같은 인자가 들어가나 네 번째 인자는 함수로 전달할 값이다.
(참고: getsockopt( )는 함수로 부터 옵션값이 저장된 버퍼의 주소값을 받아옴.)


Q. 설정한 버퍼사이즈대로 적용이 되지 않는 이유는 무엇인가?
A. TCP/IP소켓프로그래밍C page.145 상단…
   모든 사용자의 리소스를 관리하는 것은 시스템의 몫이고 소켓 버퍼크기의 조정을 할 때,
   다른 부분도 고려하기 때문에 항상 버퍼의 새로운 크기로 적용이 되는 것이 아니다.





시그널(Signal)


● 시그널이란?

 어떤 이벤트가 발생했을 때 운영체제가 프로그램에 이를 알리는 기법이다.
이러한 이벤트의 예로는 사용자가 입력한 ‘인터럽트(Interrupt)’문자 혹은 타이머가 종료된 경우를 들 수 있다.
어떤 이벤트들(그리고 이에 따른 통지(Notification))은 비동기적(Asynchronously)으로 일어나기도 하는데,
이 말은 이벤트에 대한 알림이 프로그램이 현재 실행되고 있는 명령어 위치에 관계없이 아무 때나 전달 될 수 있다는 의미이다.
현재 실행되고 있는 프로그램에 시그널이 전달되면, 다음 네 가지 중 하나의 상황이 발생한다.

  1. (운영체제에 의해) 시그널이 무시된다. 프로세스는 시그널이 도착한 것을 알지 못한다.
  2. 운영체제는 프로그램을 강제로 종료한다.
  3. 프로그램 실행이 인터럽트(Interrupt)되며, 이후에 프로그램(또는 프로그램의 일부분)이 지정한,
    시그널 처리 루틴(signal-handling routine)이 실행된다. 이 실행 루틴은 프로그램의 메인 스레드와 분리된 스레드로,
    동작하기 때문에 해당 프로그램이 시그널을 곧바로 감지할 필요가 없다.
  4. 시그널이 블로킹된다. 즉, 프로그램이 시그널을 허용할 때까지 아무런 영향을 받지 못 한다는 뜻이다.
    각 프로세스는 해당 프로세서에 어떤 시그널이 블록되어 있는지를 나타내는 마스크(Mask)를 가지고 있다.

★ TCP소켓을 사용하는 프로그램의 경우, 안정성을 위해서 반드시 SIGPIPE를 명시적으로 처리해야 한다.
   (처리를 하지 않아 메시지가 출력되었군. 소켓소멸시점 전을 확인해 봐야겠다.)



image



● TCP/IP소켓프로그래밍C p.147 SIGNAL표

종 류

이벤트

기본동작

SIGALRM

알람타이머의 만료

프로그램 종료

SIGCHLD

자식프로세스가 종료됨.

시그널무시

SIGINT

인터럽트 문자(Ctrl-C)입력됨.

프로그램 종료

SIGIO

소켓에 대해 I/O가 준비됨.

시그널무시

SIGPIPE

종료된 소켓에 쓰기를 시도할 때 발생

프로그램 종료

★ 모두 소프트웨어 인터럽트이다. (운영체제가 발생원)
★ 윈도우 프로그래밍에선 인터럽트를 메세지라고 부른다.

 

● 인터럽트문자(Ctrl-C)를 받아 처리(SIGINT)하고 세 번입력이 되면 종료되는 프로그램...sigaction.c

   1:  // sigaction.c
   2:  #include <stdio.h>
   3:  #include <signal.h>
   4:  #include <sys/types.h>
   5:  #include <unistd.h>
   6:   
   7:  int my_signal();            // 새로운 시그널 처리함수 선언
   8:  int count = 0;                // Ctrl-C입력 횟수 카운터
   9:   
  10:  int main()
  11:  {
  12:      int i = 0;
  13:   
  14:      struct sigaction act;        //sigaction구조체 변수
  15:      act.sa_handler = my_signal;    //시그널 처리함수 지정
  16:      sigemptyset(&act.sa_mask);    //sm_mask의 모든 비트를 0으로 설정
  17:      act.sa_flags = 0;
  18:   
  19:      if(SIG_ERR == sigaction(SIGINT, &act, 0))
  20:      {
  21:          fprintf(stderr, "sigaction() error \n");
  22:          exit(1);
  23:      }
  24:   
  25:      while(count < 3)
  26:      {
  27:          sleep(1);        //1초간 대기
  28:          printf("%d \n", i++);
  29:      }
  30:   
  31:      return 0;
  32:  }
  33:   
  34:  int my_signal()
  35:  {
  36:      printf("\nCtrl-C pressed \n");
  37:      count++;
  38:   
  39:      return 0;
  40:  }
  41:      


<실행결과>

image

<소스분석>

//후에 추가…

 

 

● alram( )로 설정한 시간 뒤에 발생한 SIGALRM이벤트에 프로그램이 종료되는 코드...sigalram.c

   1:  // sigalarm.c
   2:  #include <stdio.h>
   3:  #include <signal.h>
   4:  #include <sys/types.h>
   5:  #include <unistd.h>
   6:   
   7:  void timer(int sig);
   8:   
   9:  int main(void)
  10:  {
  11:      int iSec = 0;
  12:      struct sigaction act;        //sigaction구조체 변수
  13:      act.sa_handler = timer;        //시그널 처리함수 지정
  14:      sigemptyset(&act.sa_mask);    //sm_mask의 모든 비트를 0으로 설정
  15:      act.sa_flags = 0;
  16:   
  17:      if(SIG_ERR == sigaction(SIGALRM, &act, 0))
  18:      {
  19:          fprintf(stderr, "sigaction() error \n");
  20:          exit(1);
  21:      }
  22:   
  23:      alarm(5);        // 5초 후에 SIGALRM 시그널 예약
  24:      
  25:      while(1)
  26:      {
  27:          printf("%d초 경과...\n", ++iSec);
  28:          sleep(1);
  29:      }
  30:   
  31:      return 0;
  32:  }
  33:   
  34:  // 시그널 처리 함수
  35:  void timer(int sig)
  36:  {
  37:      puts("예약하신 시간이 되었습니다!! \n");
  38:      exit(0);
  39:  }
  40:      


<실행결과>

image



<소스분석>

image

//후에 추가...ㅜㅜ