A

A

다중 사용자 처리 기법2

다중 사용자 처리 기법

  •  select() 이용
  • 다중 프로세스 방식

    • 사용자(또는 클라이언트)당 하나의 프로세스를 할당함
    • preforking
  • 다중 쓰레드 방식

    • 사용자 당 하나의 쓰레드 할당
    • prethreading
  • 기타 : non-blocking socket이용, SIGIO처리

 

 다중 사용자용 TCP서버

  • listening socket 생성
  • listening socket을 이용, Client당 하나의 connected socket생성

    • Client당 한번의 accept 호출
  1. int main(int argc, char **argv)
    {
     int listenfd, connfd;
     pid_t childpid;
     socklen_t clilen;
     struct sockaddr_in cliaddr, servaddr;
     listenfd = socket(AF_INET, SOCK_STREAM, 0);
     bzero(&servaddr, sizeof(servaddr));
     servaddr.sin_family      = AF_INET;
     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
     servaddr.sin_port        = htons(SERV_PORT);
     bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
     listen(listenfd, LISTENQ);
     for ( ; ; ) {
      clilen = sizeof(cliaddr);
      connfd = accept(listenfd, (SA *) &cliaddr, &clilen);
      if ( (childpid = fork()) == 0) { /* child process */
        close(listenfd); /* close listening socket */
        str_echo(connfd); /* process the request */
        exit(0);
      }
      close(connfd); /* parent closes connected socket */
     }
    }

 

Preforking

  • 선분기

    • 사용자(또는 클라이언트)로 부터의 연결 요청 이전에 다수의 자식 프로세스를 미리 생성하여 "process pool"준비
    • 연결 요청 수신 시 가용 자식 프로세스를 특정 사용자에게 할당
    • Thundering herd 문제
  • 기존의 방법

    • 사용자로 부터의 요청을 받은 후 분기(fork)하여 자식 프로세스 생성
    • 문제점 : fork() 호출 처리 시간 ▶ 처리 지연

 

Preforking 예제

  1. static int  nchildren;
    static pid_t pids[50];
    intmain(int argc, char **argv)

     int   listenfd, i; 
     socklen_t addrlen; 
     void  sig_int(int); 
     pid_t  child_make(int, int, int);
  2.  listenfd = tcp_listen(argv[1], argv[2], &addrlen);
     nchildren = atoi(argv[argc-1]);
  3.  for (i = 0; i < nchildren; i++)
      pids[i] = child_make(i, listenfd, addrlen);
     /* parent returns */
  4.  signal(SIGINT, sig_int);
     for ( ; ; )
      pause();/* everything done by children */
    }
  5. pid_t child_make(int i, int listenfd, int addrlen)
    {
     pid_t pid;
     void child_main(int, int, int);
     if ( (pid = Fork()) > 0)  
      return(pid);  /* parent */
     child_main(i, listenfd, addrlen); /* never returns */
    }
  6. void child_main(int i, int listenfd, int addrlen)
    {
     int connfd;
     void   web_child(int);
     socklen_t  clilen;
     struct sockaddr *cliaddr;
     cliaddr = malloc(addrlen);
     printf("child %ld starting\n", (long) getpid());
     for ( ; ; ) {
      clilen = addrlen;
      connfd = accept(listenfd, cliaddr, &clilen); 
      web_child(connfd);
      /* process the request */  
      close(connfd);
     }
    }

 

Preforking 서버 구현 방식

  • 모든 자식 프로세스에서 accept() 호출

    • accept() 호출 시점에서 block되어 client로부터의 연결을 기다림
    • 하나의 자식 프로세스에서만 accept()함수가 호추되어야 할 경우 lock 이용
  • 메인 프로세스에서 accept 호출, 자식 프로세스에 descriptor를 넘기는 방식

    • UNIX domain socket, sendmsg/recvmsg 이용

 

Preforking 예제 - lock이용

     

    Descriptor passing 방식

       

      Passing descriptor

      1. int socketpair(int domain, int type, int protocol,
               int socket_vector[2]);
        UNIX domain socket 생성:
        socketpair(AF_UNIX,SOCK_STREAM,0,sockfd);
      2. ssize_t recvmsg(int sockdf, struct msghdr *msg, int flags);
        ssize_t sendmsg(int sockdf, struct msghdr *msg, int flags);
      3. struct msghdr {
            void          *msg_name;
            socklen_t     msg_namelen;    /* Length of name */
            struct iovec  *msg_iov;       /* Data blocks */
            socklen_t     msg_iovlen;     /* Number of blocks */
            void          *msg_control;   /* ancillary data */
            socklen_t     msg_controllen; /* Length of ancillary data */
            unsigned      msg_flags;
        };

       

      TCP multithreaded concurrent server

      1. int main(int argc, char **argv)
        {
         int listenfd, connfd;
         pthread_t tid, clilen, addrlen;
         struct sockaddr *cliaddr;
         listenfd = tcp_listen(argv[1], argv[2], &addrlen);
         cliaddr = malloc(addrlen);
         signal(SIGINT, sig_int);
         for ( ; ; ) {
           clilen = addrlen;
           connfd = accept(listenfd, cliaddr, &clilen);
           pthread_create(&tid, NULL, &doit, (void *) connfd);
         }
        }
      2. void *doit(void *arg)
        {
         pthread_detach(pthread_self());
         web_child((int) arg);
         close((int) arg);
         return(NULL);
        }

       

      Pre-threading

      1.  

       

      Recent Updates
        All Pages
          Show/Hide the left navigation
          Show/Hide bookmarks

          Header

          1. View current page

            sungdh86님의 노트

          loginBar