2010-02-03 2 views
0

나는 이런 식으로 뭔가가) (선택에서 실행되지 않습니다 : 나는 "타이머가 경과"고 기대했다C : 코드의 일부는

#define QUIT_TIME 5 
int main(int argc, char **argv) { 
     //... SOCKETS STUFF .... 
    fdmax = parentfd; 


    while (notdone) { 

     //Set the timers 
     waitd.tv_sec = 1; 
     waitd.tv_usec = 0; 

     FD_ZERO(&tempreadfds); 
     FD_ZERO(&tempwritefds); 

     FD_ZERO(&readfds);   /* initialize the read fd set */ 
     FD_ZERO(&writefds);   /* initialize the write fd set */ 

     FD_SET(parentfd, &readfds); /* add listener socket fd */ 
     FD_SET(0, &readfds);  /* add stdin fd (0) */ 

     tempreadfds = readfds; //make a copy 
     tempwritefds = writefds; //make a copy 

     if (select(fdmax+1, &tempreadfds, &tempwritefds, (fd_set*) 0, &waitd) < 0) { 
      error("ERROR in select"); 
     } 

     for(i = 1; i <= fdmax; i++) { 

      if(FD_ISSET(i, &readfds)) { 
       if(i == parentfd) { 
       //This is a new connection 
       childfd = accept(parentfd, (struct sockaddr *) &clientaddr, &clientlen); 
       if (childfd < 0) 
        error("ERROR on accept"); 

       InitializeDataStructures(childfd); 

       FD_SET(childfd, &readfds); //add to the master set 
       if(childfd > fdmax) 
        fdmax = childfd; 
      } else { 
       //Existing connection 
       if((nBytes = read(i, connections[i].buffer, MAXBUFFER)) <= 0) { 
        if(nBytes == 0) { 
         //Connection closed 
         printf("Socket %d hung up\n", read_write_loop); 
        } else { 
         error("\nReceive error\n"); 
        } 

        FD_CLR(i, &readfds); 
       } else { 
        //We have some data from the connection 
              //... Manipulate the buffer 
        //Handle the message 
       } 
      } 
      } 

      if(FD_ISSET(i, &writefds)) { 
           ..... 
       FD_CLR(i, &writefds); 
      } 

      //Timer checking 
      if(connections[i].active) { 
       gettimeofday(&TimeNow, NULL); 
       timeval_diff(&Interval, &TimeNow, &connections[i].TimeConnected); 
       printf("*_*_*__*_*_*__*_*_*_*_* difference is %ld seconds, %ld microseconds\n", 
         Interval.tv_sec, 
         Interval.tv_usec 
         ); 
       if(Interval.tv_sec >= QUIT_TIME) { 
        printf("Timer elapsed!!\n"); 
       } 
      } 

     } 
    } 

    /* clean up */ 
    printf("Terminating server.\n"); 
    close(parentfd); 
    return 0; 
} 

void InitializeDataStructures(int i) { 

    clients[i].active = YES; 
    clients[i].fd = i; 
    //Initialize other members of the structure 
} 

long long timeval_diff(struct timeval *difference, timeval *end_time, struct timeval *start_time) { 
     struct timeval temp_diff; 

     if(difference==NULL) 
     difference=&temp_diff; 

     difference->tv_sec =end_time->tv_sec -start_time->tv_sec ; 
     difference->tv_usec=end_time->tv_usec-start_time->tv_usec; 

     while(difference->tv_usec<0) 
     { 
     difference->tv_usec+=1000000; 
     difference->tv_sec -=1; 
     } 

     return 1000000LL*difference->tv_sec + difference->tv_usec; 

    } 

을 행합니다 (TimeConnected 적어도 한 번 매를 인쇄 할 수 있습니다 실행 중에 if 조건 중 하나로 초기화되었습니다.) 어떤 이유로 인쇄되지 않습니다. 내 while 루프가 계속 인쇄해야한다고 생각했는데 ... 어딘가에서 어수선해도 누구나 알고 있니?

편집 : 사실, 타이머를 사용하여 시간 초과 후 연결을 끊습니다. 방금 다른 클라이언트가 서버에 연결하는 경우 "Timer elapsed"라는 메시지가 출력됩니다. 선택하기 위해 최종 매개 변수를 전달했지만 왜 효과가 없는지 확신 할 수 없습니다.

덕분에 bdk !! 이 코드에있는 "어리석은"버그를 알고 싶다면 아래의 토론을 자세히 읽으십시오 ... 튜토리얼의 한 문장 때문에 간과 한 실수였습니다 : "select modifies 원래의 설명자 ". 변화의

목록 : FD_ZERO 문 세트가 잘못

  • FD_ISSET는 readfds 및 writefds 대신 tempreadfds 및 tempwritefds을 전달 받고 while 루프 내부에 배치 된 것을

    • 공지 사항 ...

    일하고 CODE :

    #define QUIT_TIME 5 
    int main(int argc, char **argv) { 
         //... SOCKETS STUFF .... 
        fdmax = parentfd; 
    
    
        FD_ZERO(&readfds);   /* initialize the read fd set */ 
        FD_ZERO(&writefds);   /* initialize the write fd set */ 
    
        while (notdone) { 
    
         //Set the timers 
         waitd.tv_sec = 1; 
         waitd.tv_usec = 0; 
    
         FD_ZERO(&tempreadfds); 
         FD_ZERO(&tempwritefds); 
    
    
         FD_SET(parentfd, &readfds); /* add listener socket fd */ 
         FD_SET(0, &readfds);  /* add stdin fd (0) */ 
    
         tempreadfds = readfds; //make a copy 
         tempwritefds = writefds; //make a copy 
    
         if (select(fdmax+1, &tempreadfds, &tempwritefds, (fd_set*) 0, &waitd) < 0) { 
          error("ERROR in select"); 
         } 
    
         for(i = 1; i <= fdmax; i++) { 
    
          if(FD_ISSET(i, &tempreadfds)) { 
           if(i == parentfd) { 
           //This is a new connection 
           childfd = accept(parentfd, (struct sockaddr *) &clientaddr, &clientlen); 
           if (childfd < 0) 
            error("ERROR on accept"); 
    
           InitializeDataStructures(childfd); 
    
           FD_SET(childfd, &readfds); //add to the master set 
           if(childfd > fdmax) 
            fdmax = childfd; 
          } else { 
           //Existing connection 
           if((nBytes = read(i, connections[i].buffer, MAXBUFFER)) <= 0) { 
            if(nBytes == 0) { 
             //Connection closed 
             printf("Socket %d hung up\n", read_write_loop); 
            } else { 
             error("\nReceive error\n"); 
            } 
    
            FD_CLR(i, &readfds); 
           } else { 
            //We have some data from the connection 
                  //... Manipulate the buffer 
            //Handle the message 
           } 
          } 
          } 
    
          if(FD_ISSET(i, &tempwritefds)) { 
               ..... 
           FD_CLR(i, &writefds); 
          } 
    
          //Timer checking 
          if(connections[i].active) { 
           gettimeofday(&TimeNow, NULL); 
           timeval_diff(&Interval, &TimeNow, &connections[i].TimeConnected); 
           printf("*_*_*__*_*_*__*_*_*_*_* difference is %ld seconds, %ld microseconds\n", 
             Interval.tv_sec, 
             Interval.tv_usec 
             ); 
           if(Interval.tv_sec >= QUIT_TIME) { 
            printf("Timer elapsed!!\n"); 
           } 
          } 
    
         } 
        } 
    
        /* clean up */ 
        printf("Terminating server.\n"); 
        close(parentfd); 
        return 0; 
    } 
    
    void InitializeDataStructures(int i) { 
    
        clients[i].active = YES; 
        clients[i].fd = i; 
        //Initialize other members of the structure 
    } 
    
    long long timeval_diff(struct timeval *difference, timeval *end_time, struct timeval *start_time) { 
         struct timeval temp_diff; 
    
         if(difference==NULL) 
         difference=&temp_diff; 
    
         difference->tv_sec =end_time->tv_sec -start_time->tv_sec ; 
         difference->tv_usec=end_time->tv_usec-start_time->tv_usec; 
    
         while(difference->tv_usec<0) 
         { 
         difference->tv_usec+=1000000; 
         difference->tv_sec -=1; 
         } 
    
         return 1000000LL*difference->tv_sec + difference->tv_usec; 
    
        } 
    
  • +0

    괄호가 불균형 한 것처럼 보입니다. –

    +0

    오, 여기에 코드를 입력하고있었습니다 ... 오타가 있었음에 틀림 없습니다 ... 지금 고치십시오 ... – Legend

    +0

    코드를 복사하여 붙여 넣는 것이 어떨까요? 그러면 실제로 무엇이 있는지 알 수 있습니다. 바보 같은 오타가 생겼어? –

    답변

    1

    선택 루프 매개 변수를 살펴보면 필자에게 어수선해 보입니다. 주로 tempreadfd 및 tempwritefd에서 select를 호출하지만 FD_ISSET을 호출하면 readfd 및 writefd를 전달합니다. select를 호출하기 전에 FD_SET을 사용하여 관심있는 모든 fd를 설정합니다.이 변수가 선택되지 않기 때문에 트리거되지 않은 fds는 마스크되지 않습니다. 따라서 모든 설명자에서 '활동'이 감지됩니다. 그 accept descriptor에는 아무런 활동도 없기 때문에 새로운 클라이언트가 연결될 때까지 차단됩니다.

    내 생각에 적어도.

    +0

    select가 원본 설명자를 수정하기 때문에 readfds 및 writefds의 복사본을 전달하는 이유는 다음과 같습니다. 적어도 스티븐스 (Stevens)의 맨 페이지와 유닉스 네트워크 프로그래밍 서적에 쓰여진 것입니다 ... – Legend

    +0

    예, 사본을 선택 항목으로 전달하지만 FD_ISSET에 동일한 사본을 전달하십시오 – bdk

    +0

    시도해 봅니다. ... 잠깐 후에 돌아올거야 ... – Legend

    0

    이것은 매우 특정한 코드 문제이지만 다른 사람들에게 도움이 될지도 모릅니다. 문제를 해결하기 위해 스레드를 사용하는 것으로 끝났습니다 (최고는 아니지만, 이걸 디버깅하려고하는 너트가 ...). 나 좀 도와 인내심을 가지고 모두에게 감사합니다 ... 위의 코드에서

    대신) (주의 while 루프 내부의 타이머를 테스트하는 다음과 같이 내가 그것을 수정 :

    if(ThreadSpawned == 0) { 
           pthread_create(&thread, NULL, cleanup, (void *) &fdmax); 
           ThreadSpawned = 1; 
          } 
    

    그런 다음 정리 기능은 다음과 같습니다.

    void *cleanup(void *arg) { 
        //Timer checking 
        int i, *fdmax; 
        fdmax = (int *) arg; 
    
        while(1) { 
         for(i = 1; i <= *fdmax; i++) { 
          if(connections[i].active == 1) { 
           gettimeofday(&TimeNow, NULL); 
           timeval_diff(&Interval, &TimeNow, &clients[i].TimeConnected); 
           printf("*_*_*__*_*_*__*_*_*_*_* difference is %ld seconds, %ld microseconds\n", 
             Interval.tv_sec, 
             Interval.tv_usec 
           ); 
           fflush(stdout); 
           if((int) Interval.tv_sec >= QUIT_TIME) { 
            printf("Timer elapsed!!\n"); 
            fflush(stdout); 
           } 
          } 
         } 
         sleep(20); 
        } 
    } 
    

    더 깨끗한 솔루션을 사용하는 것이 가장 좋습니다. 아마도 bdk가 대답 한 이유 중 하나는 프로그램이 승인에서 차단하는 이유이지만 차단되면 차단 시간을 계산할 방법이 없을 것입니다. 그래서 스레드를 사용하여 끝났습니다. 이 작업을 수행하십시오 ...

    1

    코드를 올바르게 읽는 경우 while 루프를 입력 한 다음 설명자가 읽기 세트에 있는지 확인하십시오. 그럴 경우 if 문에서 accept() 부분으로 이동합니다.그렇지 않으면 else 부분을 입력합니다. 여기서 else 부분을 사용하면 읽은 내용을 즉시 차단할 수 있습니다. 소켓이 활성화되어 있으면 사용할 수있는 데이터가 없으므로 데이터가 사용 가능해질 때까지 차단합니다. 입력에 대한 성공적인 읽기 또는 오류를 얻을 때까지 타이머를 점검하는 섹션까지 빠져 나가지 않습니다.

    select가 0보다 큰 값을 반환하는 경우에만 소켓을 검사하는 코드를 입력해야합니다. 그런 다음 소켓에서 읽기를 시도하기 전에 소켓이 읽기 집합에 있는지 확인해야합니다.

    일반적으로 하나의 fdset을 만들어 연결을 수락하는 소켓과 수락하고 실제로 데이터를 읽는 소켓을 확인합니다. 나는 당신이 제시 한 방식대로 할 수 있다고 생각하지만, read()에서 recv()로 전환하고 MSG_PEEK 플래그를 사용하는 것이 좋습니다.

    관련 문제