깊이 이해 유 닉 스 / linux 시리즈 중 Select () 모델 [중 영 대조]

문장 을 번역 하 는 것 은 자신 을 위해 더욱 잘 이해 하기 위해 서 이다.영문http://www.doserver.net/post/linux-unix-select-model.php 길림대학 호장 우 박사의 개인 홈 페이지 입 니 다.
THE WORLD OF SELECT() So just why am I so hyped on select()? One traditional way to write network servers is to have the main server block on accept(), waiting for a connection. Once a connection comes in, the server fork()s, the child process handles the connection and the main server is able to service new incoming requests. With select(), instead of having a process for each request, there is usually only one process that "multi-plexes" all requests, servicing each request as much as it can. So one main advantage of using select() is that your server will only require a single process to handle all requests. Thus, your server will not need shared memory or synchronization primitives for different 'tasks' to communicate. One major disadvantage of using select(), is that your server cannot act like there's only one client, like with a fork()'ing solution. For example, with a fork()'ing solution, after the server fork()s, the child process works with the client as if there was only one client in the universe -- the child does not have to worry about new incoming connections or the existence of other sockets. With select(), the programming isn't as transparent.
select () 의 세계 - 왜 나 는 select () 에 이렇게 열광 합 니까?
        네트워크 서버 프로그램 을 작성 할 때 전통 적 인 방법 은 주요 서비스 코드 를 accept () 블록 에 넣 고 연결 을 기다 리 는 것 입 니 다.연결 이 도착 하면 서버 는 포크 () 함 수 를 호출 하여 하위 프로 세 스 를 생 성하 여 이번 연결 을 처리 합 니 다. 그 다음 에 메 인 서 비 스 는 새로운 연결 요청 을 받 아들 일 수 있 습 니 다.
        select () 가 있 으 면 서버 는 모든 연결 에 하나의 프로 세 스 를 만 들 필요 가 없 으 며, 같은 프로 세 스에 서 모든 연결 요청 을 처리 하여 다 중 재 활용 을 실현 하고 모든 연결 서 비 스 를 위해 최선 을 다 할 수 있 습 니 다.
        이렇게 보면 select () 의 가장 큰 장점 은 서버 가 시스템 에 하나의 프로 세 스 만 신청 하면 모든 연결 요청 을 처리 하여 서버 가 메모리 공유 나 서로 다른 작업 간 의 동기 화 원 어 통신 에서 벗 어 날 수 있다 는 것 이다.
        그러나 select () 도 단점 이 있 습 니 다. 가장 중요 한 것 은 서버 가 '클 라 이언 트 가 하나 밖 에 없다' 는 가설 에서 실행 되 지 못 하고 fork () 처럼 문 제 를 해결 할 수 없다 는 것 입 니 다.예 를 들 어 서버 가 fork () 후 하위 프로 세 스 를 호출 하여 클 라 이언 트 를 처리 할 때 마치 전 세계 에 이 클 라 이언 트 만 존재 하 는 것 같 습 니 다. 나중에 클 라 이언 트 연결 요청 이나 기 존의 소켓 을 걱정 할 필요 가 없습니다.select () 는 모든 소켓 을 이렇게 투명 하 게 대하 지 않 습 니 다.
Okay, so how do you use select()? select() works by blocking until something happens on a file descriptor (aka a socket). What's 'something'? Data coming in or being able to write to a file descriptor -- you tell select() what you want to be woken up by. How do you tell it? You fill up a fd_set structure with some macros. Most select()-based servers look pretty much the same:
그럼 select () 는 어떻게 사용 하나 요?
        select () 의 작업 방식 은 파일 설명자 (즉 socket) 에서 지정 한 이벤트 가 실 행 될 때 까지 차단 하 는 것 입 니 다.어떤 사건 이 죠?데이터 가 전송 되 거나 파일 설명 자 를 쓸 준비 가 되 어 있 습 니 다. 이것 은 모두 select () 가 어떤 사건 에 촉발 되 고 싶 은 지 알려 줍 니 다.어떻게 알려 줘 요?매크로 명령 으로 fd 작성set 구조 체.
        대부분의 select () 함 수 를 기반 으로 한 서버 는 매우 비슷 한 구 조 를 가지 고 있다.
Fill up a fd_set structure with the file descriptors you want to know when data comes in on.
                    fd_set
Fill up a fd_set structure with the file descriptors you want to know when you can write on.
                 fd_set
Call select() and block until something happens.  select()          Once select() returns, check to see if any of your file descriptors was the reason you woke up. If so, 'service' that file descriptor in whatever particular way your server needs to (i.e. read
 in a request for a Web page).  select()    ,       ,        。     ,                    。Repeat this process forever.       。
Quit with the pseudo-code, show me some real code!Okay, let's take a look at a sample server included with Vic Metcalfe's Socket Programming FAQ (my comments are in red):


        , !

        , Vic Metcalfe's Socket Programming FAQ ( )

/*  
   PLEASE READ THE FILE NB-APOLOGY!!!!  There are some things you should 
   know about this source before you read it.  Thanks. 
        NB-APOLOGY (http://www.lowtek.com/sockets/NB-APOLOGY.txt),                     。  !
    
   Quang Ngo alerted me to a bug where the variable listnum in deal_with_data() 
   wasn't being passed in by parameter, thus it was always garbage. I have 
   quick-fixed this in the code below. - Spencer (October 12, 1999) 
   Quang Ngo       deal_with_data()     listnum         ,         。          。-Spencer(1999.10.12)
 
   Non blocking server demo  
   By Vic Metcalfe ([email protected]) 
   For the unix-socket-faq 

             
     :Vic Metcalfe ([email protected])
    unix-socket-faq  
 */  
  
#include "sockhelp.h"  
#include <ctype.h>  
#include <sys/time.h>  
#include <fcntl.h>  
  
int sock;            /*              */  
int connectlist[5];  /*      socket  ,             */  
fd_set socks;        /*      select()     socket     */  
int highsock;       /* select()               */  
  
void setnonblocking(sock)  
int sock;  
{  
  int opts;  
  
  opts = fcntl(sock,F_GETFL);  
  if (opts < 0) {  
    perror("fcntl(F_GETFL)");  
    exit(EXIT_FAILURE);  
  }  
  opts = (opts | O_NONBLOCK);  
  if (fcntl(sock,F_SETFL,opts) < 0) {  
    perror("fcntl(F_SETFL)");  
    exit(EXIT_FAILURE);  
  }  
  return;  
}
void build_select_list() {  
  int listnum;       /* connectlist   for             */  
      
  /*    fd_set select()     ,     sock          ,       sockets   */  
        
        
  /* FD_ZERO()    fd_set      ,                */  
        
  FD_ZERO(&socks);  
        
  /* FD_SET()   “sock” fd_set  ,           select()       (      accept()  )*/  
        
  FD_SET(sock,&socks);  
        
  /*                      fd_set  */  
        
  for (listnum = 0; listnum < 5; listnum++) {  
    if (connectlist[listnum] != 0) {  
      FD_SET(connectlist[listnum],&socks);  
      if (connectlist[listnum] > highsock)  
        highsock = connectlist[listnum];  
    }  
  }  
}  
void handle_new_connection() {  
  int listnum;       /* connectlist   for             */  
  int connection; /*      socket     */  
  
  /*      !    connectlist            */  
  connection = accept(sock, NULL, NULL);  
  if (connection < 0) {  
    perror("accept");  
    exit(EXIT_FAILURE);  
  }  
  setnonblocking(connection);  
  for (listnum = 0; (listnum < 5) && (connection != -1); listnum ++)  
    if (connectlist[listnum] == 0) {  
      printf("
Connection accepted: FD=%d; Slot=%d
", connection,listnum); connectlist[listnum] = connection; connection = -1; } if (connection != -1) { /* No room left in the queue! */ printf("
No room left for new client.
"); sock_puts(connection,"Sorry, this server is too busy. " Try again later!\r
"); close(connection); } }
void deal_with_data(  
  int listnum      /* connectlist   for             */  
  ) {  
  char buffer[80];     /* socket     */  
  char *cur_char;      /*          */  
  
  if (sock_gets(connectlist[listnum],buffer,80) < 0) {  
    /*      ,      connectlist  */  
    printf("
Connection lost: FD=%d; Slot=%d
", connectlist[listnum],listnum); close(connectlist[listnum]); connectlist[listnum] = 0; } else { /* , */ printf("
Received: %s; ",buffer); cur_char = buffer; while (cur_char[0] != 0) { cur_char[0] = toupper(cur_char[0]); cur_char++; } sock_puts(connectlist[listnum],buffer); sock_puts(connectlist[listnum],"
"); printf("responded: %s
",buffer); } }
void read_socks() {  
  int listnum;       /* connectlist   for             */  
  
  /*   socket      sock     ,        socket,    connectlist  socket*/  
    
  /*          connect()        socket,select()     socket    。
       ,       socket fd_set   ,          。*/  
    
  if (FD_ISSET(sock,&socks))  
    handle_new_connection();  
  /*  connectlist       */  
    
  /*    socket,           ,   ,    */  
    
  for (listnum = 0; listnum < 5; listnum++) {  
    if (FD_ISSET(connectlist[listnum],&socks))  
      deal_with_data(listnum);  
  } /*for  (       )*/  
}
int main (argc, argv)   
int argc;  
char *argv[];  
{  
  char *ascport;  /*     ASCII */  
  int port;       /* ACII        */  
  struct sockaddr_in server_address; /*           */  
  int reuse_addr = 1;  /*                  TIME_WAIT        */  
  struct timeval timeout;  /* select     */  
  int readsocks;       /*       socket */  
      
  /*                    */  
  if (argc < 2) {  
    printf("Usage: %s PORT\r
",argv[0]); exit(EXIT_FAILURE);   } /* socket */ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); exit(EXIT_FAILURE); } /* TIME_WAIT */ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); /* sernonblocking socket */ setnonblocking(sock); /* , socket*/ ascport = argv[1]; /* */ port = atoport(ascport); /* sockhelp int */ memset((char *) &server_address, 0, sizeof(server_address)); server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = htonl(INADDR_ANY); server_address.sin_port = port; if (bind(sock, (struct sockaddr *) &server_address, sizeof(server_address)) < 0 ) {   perror("bind"); close(sock); exit(EXIT_FAILURE); } /* */ listen(sock,5); /* socket, socket */ highsock = sock; memset((char *) &connectlist, 0, sizeof(connectlist)); while (1) { /* */ build_select_list(); timeout.tv_sec = 1; timeout.tv_usec = 0; /* select() +1, FD_SETSIZE */ /* select() socket fd_set ( socket)*/ /* select() fd_set, , 0 NULL。*/
    /* select()            OOB  (    )sockets,  ,   */
          
    /* select()              。               ,   NULL*/  
          
    readsocks = select(highsock+1, &socks, (fd_set *) 0, (fd_set *) 0, &timeout);  
          
    /* select()        socket,     socket*/  
            
     /*   select()     ,  fd_set         select()   。
         :4          fd_set,         ,fd_set    */  
          
    if (readsocks < 0) {  
      perror("select");  
      exit(EXIT_FAILURE);  
    }  
    if (readsocks == 0) {  
      /*       , “.”   */  
      printf(".");  
      fflush(stdout);  
    } else  
      read_socks();  
  } /* while(1) */  
} /* main */  

Okay, so maybe that wasn't the best example...



Got some suggests? Corrections? Please let me know.

, 。

In the mean time, here's some references to other sources of information about select():

, select()

Socket FAQ Question about select()
Straight from the excellent socket FAQ.

socket FAQ

Unix Programming FAQ Question about select()
Straight from the other excellent FAQ.

        socket FAQ
Unix Socket Programming FAQ Examples
The above nbserver.c sample code and more socket stuff.
이상 nbserver. c 소스 코드 및 더 많은 socket 루틴
thttpd - tiny/turbo/throttling HTTP server
작은 단일 스 레 드, 비 fork (), select () 기반 웹 서버.
BOA
Another single-threaded, select() based Web server.
      ,   select() Web   .
   

좋은 웹페이지 즐겨찾기