select함수를 이용한 에코서버에서 궁금한게있습니다.

korisaram의 이미지

1:  int main(int argc, char **argv)
2:  {
3:  int serv_sock;
4:    struct sockaddr_in serv_addr;
5:
6:   fd_set reads, temps;
7:  int fd_max;
8:  
9:  char message[BUFSIZE];
10:   int str_len;
11:   struct timeval timeout;
12:
13:  if(argc!=2){
14:    printf("Usage : %s <port>\n", argv[0]);
15:    exit(1);
16:  }
17:
18:  serv_sock = socket(PF_INET, SOCK_STREAM, 0);
19:  serv_addr.sin_family = AF_INET;
20:  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
21:  serv_addr.sin_port = htons(atoi(argv[1]));
22:
23:  if(bind(serv_sock, (struct sockaddr *) &serv_addr, sizeof (serv_addr)))
24:    error_handling("bind() error");
25:  if(listen(serv_sock, 5)==-1)
26:    error_handling("listen() error");
  
27:  FD_ZERO(&reads);
28:  FD_SET(serv_sock, &reads);
29:  fd_max=serv_sock;
30:
31:  while(1)
32:  {
33:    int fd, str_len;
34:    int clnt_sock, clnt_len;
35:    struct sockaddr_in clnt_addr;
36:
37:    temps=reads;
38:    timeout.tv_sec = 5;
39:    timeout.tv_usec = 0; 
40:    
41:    if(select(fd_max+1, &temps, 0, 0, &timeout)==-1)
42:		error_handling("select() error");	
43:
44:    for(fd=0; fd<fd_max+1; fd++)
45:    {
46:      if(FD_ISSET(fd, &temps))
47:      {
48:		if(fd==serv_sock) { /* 연결 요청인 경우 */
49:		  clnt_len = sizeof(clnt_addr);
50:  clnt_sock = accept(serv_sock, (struct    sockaddr *)&clnt_addr, &clnt_len);
51:		  FD_SET(clnt_sock, &reads);
52:		  if(fd_max<clnt_sock)
53:		    fd_max=clnt_sock;
54:  printf("클라이언트 연결 : 파일 디스크립터 %d \n", clnt_sock);
55:		}
56:		else {
57:		  str_len = read(fd, message, BUFSIZE);
58:		  if(str_len ==0){ /* 연결 종료 요청인 경우 */
59:		    FD_CLR(fd, &reads);
60:		    close(fd);
61:     printf("클라이언트 종료 : 파일 디스크립터 %d \n", fd);
62:		  }
63:		  else{
64:		    write(fd, message, str_len); 
65:		  }	
66:		}
67:       } //if(FD_ISSET(fd, &temps))
68:     } //for(fd=0; fd<fd_max+1; fd++)
69:   } //while(1)
70:   }

위코드는 select문으로 만든 echo서버입니다. 제가 공부하는 책 예제인데
분석하다 보니 이해가 안가는 부분이있어서 질문들립니다.

44행에서 fd를 0부터 시작해서 서버소켓까지 for문으로 돌리고 있습니다.
fd가 0은 표준입력,1은 표준출력,2는 표준 에러라고 알고있습니다.
제생각으로는 fd를 3부터 for문으로 돌려서 클라이언트가 접속시도할때마다
어떤대응을 하게 만들어야할것 같은데 왜 0부터 for루프를 돌리는 지가
궁금합니다.

그리고 꼭 for문을 0부터 돌려야한다면 fd가 0일때 57행이 실행되어서
키보드로 값을 입력하면 그게 읽혀질건데 왜 서버에 저런게 필요한지도
궁금합니다.

익명 사용자의 이미지

누군가 답글 달아주실거라 사료되어 그냥 있었는데
이론~ 썰렁~

굉장히 복잡한거 같으면서도 괜찮군요.....
좋은 기법인거 같네요. 단지 이것은 동시 1024(Linux에서)개 이상의 클라이언트를
받지 못하는 단점이 있어요......

일단 반드시 0,1,2 가 예약이 아닐수도 있다는 점.
누군가가 프로그램이 시작되고서 표준입/출력 을 전부 close한다면
그 만큼 핸들에 여유가 생기고 원하지 않는 입출력을 막을수 있겠죠?

main에서

int i;
for(i = 0;i < 3;i++)close(i);

이렇게 해보세요. 이게 어떻게 되버리는지.... 기가막히죠?
확인은 /proc/<pid>/fd 아시죠?

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.