0

퀴즈 응용 프로그램을 만들어야합니다. 응용 프로그램에 대한기능 동작 선택 - 다중 클라이언트 퀴즈

세부 사항 :
1. 각 클라이언트가 퀴즈에 참여하기 전에 서버에 등록 할 수 있습니다. 서버는 각 사용자의 사용자 이름을 물어보고 각 사용자에 대한 임시 ID를 생성합니다.
2. 등록 프로세스 후 클라이언트에 성공적으로 연결된 서버는 질문입니다.
3. 클라이언트가 응답으로 응답합니다.
4. 서버는 타임 스탬프가있는 다른 클라이언트의 응답을 수신하며, Δt라고하는 각 클라이언트의 시간 차이는 입니다.

Define such as: 
    ∆t = (Time Question sent - Time answer received) - RTT 
    Where RTT is Round Trip Time 
  1. 서버는, 그 ΔT는 모두 최소하고 점수를 얻을하지 않습니다 유물을 얻을 것입니다 어떤 점수를 클라이언트로 응답 클라이언트를 선택합니다.
  2. 보낸 후 질문 서버는 (T)라는 특정 기간 동안 응답을 기다립니다. 클라이언트가 'T'시간 내에 응답하지 않으면 Server는 해당 질문을 건너 뛰고 다음 질문으로갑니다. 내 서버 코드

    A. A main while loop which runs once for each question. 
    B. Inside this first I am accepting login for 10 seconds. 
         Here I am assigning user Id and all other initialization stuff. 
    C. Then using `select` to check which are available for writing. 
         To available connections I am checking `RTT` and then sending question to each user. 
    D. Then I am waiting for some time to get answers. 
         Here I am using `select` to determine where the answer is available to read. 
    E. Then I am repeating steps C. and D. 
    

    문제의 메인 루프의

의사 코드는 : 나는 하나의 클라이언트 만 연결하면
내 코드는 질문의 수에 대해 잘 작동합니다.
하지만 같은 클라이언트 코드를 여러 클라이언트에서이 코드를 테스트 할 때 : 모두를위한

  • 로그인 OK입니다.
  • 모든 사람에게 첫 번째 질문 보내기가 잘 작동합니다.
  • 그런 다음 응답을 기다리는 동안 한 클라이언트에서만 답변을 받았습니다. 각 클라이언트는 응답이 전송되었음을 보여줍니다. 두 번째 클라이언트의 경우 두 번째 select 함수는 읽을 수있는 데이터 가용성을 반환하지 않습니다.

내 클라이언트 코드가 작동하지 않는 이유는 무엇입니까? (내 말에 따르면, 오류는 답을 얻는 데 어딘가에있다.)

내 코드 :
패킷의 구조는 변수 이름에서 쉽게 이해 될 수 보내 .

Server.c :

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <error.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <arpa/inet.h> 
#include <sys/wait.h> 
#include <signal.h> 
#include <time.h> 

#define PORT "3490" //the port user will be connecting to 
#define BACKLOG 10 //how many pending connection queue will hold 
#define maxUser 10 
#define LOGIN_OK "OK" 
#define LOGIN_WrongPassword "NP" 
#define LOGIN_WrongUsername "NU" 
#define MAX_USERS 10 
#define MAX_ANSWER_TIME 10 
#define LOGIN_WAIT 10 
#define TOTAL_QUES "3" 

int users[MAX_USERS][3] = {}; //index is userID, 0 is no user 

void sigchld_handler(int s) 
{ 
    while(waitpid(-1, NULL, WNOHANG) > 0); 
} 

//get sockaddr, IPv4 or IPv6 

int timer; 
void alarm_handler(int s) { 
    timer = 0; 
} 

wrongRecv(ssize_t recvd, ssize_t expctd) 
{ 

    if(recvd != expctd) 
    { 
     printf("Recvd(%zd) bytes not equal to expected(%zd) bytes\n",recvd,expctd); 
     //getchar(); 
    } 
} 

//void nextQues(char* quesMsg, char* ques, char* optA, char* optB, char* optC, char* optD) 
int nextQues(char* quesMsg, int QID) 
{ 
    char ques[40], optA[10], optB[10], optC[10], optD[10], quesId[5]; 

    sprintf(quesId,"%d",QID); 
    strncpy(ques, "This is the question?",22); 
    strncpy(optA, "OptionA", 7); strncpy(optB, "OptionB", 7); strncpy(optC, "OptionC", 7); strncpy(optD, "OptionD", 7); 
    strncpy(quesMsg,quesId,5); 
    strncpy(quesMsg + 05,ques,40); 
    strncpy(quesMsg + 45,optA,10); 
    strncpy(quesMsg + 55,optB,10); 
    strncpy(quesMsg + 65,optC,10); 
    strncpy(quesMsg + 75,optD,10); 

    return 0; 
} 

//void answerCheck(char* ques, char* optA, char* optB, char* optC, char* optD, char* usrResponse, int rtt, int timeTaken) 
void answerCheck(int fd, char usrResponse[6], int rtt, int timeTaken) 
{ 
    int responseTime, i; 
    char actualAnswer[1]; 
    char quesId[5]; 
    printf("fd(%d) quesid(%s) response(%c) rtt(%d) timeTaken(%d)\n", fd, usrResponse, usrResponse[5], rtt, timeTaken); 
    strncpy(quesId, usrResponse, 5); 
    actualAnswer[0] = 'B';//we have quesId we can find actual answer on basis of it 

    if(actualAnswer[0] == usrResponse[5]) 
    { 
     //printf("%s\n","+++++"); 
     responseTime = timeTaken - rtt; 
     //printf("Response Time(%d)\n",responseTime); 

     //save it with user id 

     //finding userid 
     for(i = 0; i < MAX_USERS; i++) { 
      if(users[i][1] == fd) { 
       users[i][2] = responseTime;//saving it 
       //printf("%d\n",i); 
      } 
     } 
    } 
} 

int compareAnswer() { 
    int i, min = 2 * MAX_ANSWER_TIME, userIndex; 
    for(i = 0; i < MAX_USERS; i++) { 
     if(users[i][2] < min) { 
      min = users[i][2]; 
      userIndex = i; 
     } 
    } 
    //Increasing Score 
    users[userIndex][0]++; 

    //returning fd 
    return users[userIndex][1]; 
} 

void users_deleteFd(int fd) { 
    int i; 
    for (i = 0; i < MAX_USERS; ++i) 
    { 
     if(users[i][1] == fd) { 
      users[i][1] =0; 
      return; 
     } 
    } 
} 

int rtt_check(int new_fd) 
{ 
    ssize_t send_ret, recv_ret; 
    char rtt_check[1]; 
    time_t rtt1, rtt2; 

    rtt1 = time(NULL); 
    send_ret = send(new_fd, "r", 1, 0); 
    if(send_ret == 0) 
    { 
     return -2; 
    } 
    wrongRecv(send_ret, 1); 
    //printf("%s\n","Between two phase of rttCheck"); 
    recv_ret = recv(new_fd, rtt_check, 1,0); 
    rtt2 = time(NULL); 
    if(recv_ret == 0) 
    { 
     return -2; 
    } 
    wrongRecv(recv_ret,1); 
    //printf("diff(%d)\n",(int) difftime(rtt2,rtt1)); 

    return (int) difftime(rtt2,rtt1); 
} 

int login(char user[], char pass[]) 
{ 
    //for user 
    static int Id = 0; //when have function getUserID, make it not static and also remove Id++; 
    if(!strcmp(user,"abhishek") && !strcmp(pass,"abhishek")) { 
     //Id = getUserID(user); 
     return ++Id; 
    }else if(!strcmp(user,"abhishek")){ 
     return 0; //wrong password 
    } 
    return -1; //wrong username 
} 

int totalQues; 

int login_setup(int new_fd) 
{ 
    //login inititalizations 
    char login_det[16]; 
    char username[9],password[9], login_statMsg[7], totalQuesMsg[5] = TOTAL_QUES; 
    totalQues = atoi(totalQuesMsg); 
    //for user 
    int userId; 

    //for wrongRecv 
    ssize_t send_ret,recv_ret; 

    //getting username and password 
    recv_ret = recv(new_fd,login_det,16,0); 
    if(recv_ret == 0) 
    { 
     return -2; 
    } 
    wrongRecv(recv_ret,16); 

    //extracting username nad password 
    strncpy(username,login_det,8); 
    strncpy(password,login_det+8,8); 
    username[8]='\0'; password[8]='\0'; 
    //printf("username(%s) and password(%s)\n",username,password); 

    if((userId = login(username,password)) > 0) { 
     //printf("%d\n",userId); 

     //sending status 
     strncpy(login_statMsg, LOGIN_OK, 2); 
     strncpy(login_statMsg + 2, totalQuesMsg , 5); 
     send_ret = send(new_fd, login_statMsg,7,0); 
     if(send_ret == 0) 
     { 
      return -2; 
     } 
     wrongRecv(send_ret,7); 

     //TODO error checking then handling if error 

     //users[userId][0] = 0; //score 
     users[userId][1] = new_fd; //file descriptor associated with this user 
     //users[userId][2] = 0; //answer time 
     return 1; 
    } 
    else if(userId == -1) { //wrong username 
     strncpy(login_statMsg, LOGIN_WrongUsername, 2); 
     strncpy(login_statMsg + 2, totalQuesMsg , 5); 
     send_ret = send(new_fd, login_statMsg,7,0); 
     if(send_ret == 0) 
     { 
      return -2; 
     } 
     wrongRecv(send_ret,7); 
     return 0; 
    } 
    else{ 
     strncpy(login_statMsg, LOGIN_WrongPassword, 2); 
     strncpy(login_statMsg + 2, totalQuesMsg , 5); 
     send_ret = send(new_fd, login_statMsg,7,0); 
     if(send_ret == 0) 
     { 
      return -2; 
     } 
     wrongRecv(send_ret,7);  
     return 0; 
    } 
    //TODO erorr handling of above two case 
    //TODO make login a loop 
} 


void *get_in_addr(struct sockaddr *sa) 
{ 
    if (sa->sa_family == AF_INET) { 
     return &(((struct sockaddr_in*)sa)->sin_addr); 
    } 

    return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 


int main(void) 
{ 
    int listen_fd, new_fd; // listen on sock_fd, new connection on new_fd 
    struct addrinfo hints, *servinfo, *p; 
    struct sockaddr_storage their_addr;//connection's address info 
    socklen_t sin_size; 
    int yes=1; 
    char s[INET6_ADDRSTRLEN]; 
    int rv; 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC;//IPv4 or IPv6 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; // use my IP 

    if((rv = getaddrinfo(NULL,PORT, &hints, &servinfo)) != 0){ //getting which IPv server supports 
     fprintf(stderr, "getaddrinfo: %s\n",gai_strerror(rv)); 
     return 1; 
    } 

    //loop through all the result and bind to the first we can 
    for(p = servinfo; p != NULL; p = p->ai_next){ 
     if((listen_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){ 
      perror("server : socket"); 
      continue; 
     } 

     if(setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){ 
      perror("set sockopt"); 
      exit(1); 
     } 

     if(bind(listen_fd, p->ai_addr, p->ai_addrlen) == -1){ 
      close(listen_fd); 
      perror("server: bind"); 
      continue; 
     } 

     break; 
    } 

    if(p == NULL) { 
     fprintf(stderr, "server:failed to bind\n"); 
     return 2; 
    } 

    freeaddrinfo(servinfo);//all done with this structure 

    if(listen(listen_fd, BACKLOG) == -1){ 
     perror("listen"); 
     exit(1); 
    } 
    //printf("listen_fd(%d)\n",listen_fd); 

// sa.sa_handler = sigchld_handler; // reap all dead processes 
// sigemptyset(&sa.sa_mask); 
// sa.sa_flags = SA_RESTART; 
// if(sigaction(SIGCHLD, &sa, NULL) == -1){ 
//  perror("sigaction"); 
//  exit(1); 
// } 

    printf("server waiting for connections.....\n"); 

    fd_set master; //master file descriptor list 
    fd_set read_fds; //temp file descriptor list for select() 
    int fdmax; 
    FD_ZERO(&master); //clear the master and temp sets 
    FD_ZERO(&read_fds); 

    FD_SET(listen_fd, &master); 

    //keep track of the bigge file descriptor 
    fdmax = listen_fd; // so far it is this one 

    ssize_t recv_ret, send_ret; 


    //for login 
    int loginStatus; 
    struct sigaction sa; 
    sa.sa_handler = alarm_handler; 
    sigemptyset(&sa.sa_mask); 
    //sa.sa_flags = SA_RESTART; 
    if(sigaction(SIGALRM, &sa, NULL) == -1){ 
     perror("sigaction"); 
     exit(1); 
    } 


    //login while 
    alarm(LOGIN_WAIT);//accepting login only for 10 seconds 
    timer = 1; 
    printf("\n-----------------------------Waiting for users to login for %d seconds.-----------------------------\n",LOGIN_WAIT); 
    while(timer) { 
     sin_size = sizeof their_addr; 
     new_fd = accept(listen_fd, (struct sockaddr *)&their_addr, &sin_size); 
     if(new_fd == -1){ 
      //perror("accept"); 
      break;// this break is very important , as we are using alarm(Signals) and accept is a blocking function 
        //If accept is in blocked sate and our signal comes then accept will exit returning error. So 
        //if error then we have to break else next satements will run on falsy values. 
        //In reality we dont need this as I alredy set the SA_RESTART flag in sigaction which means 
        //after returning from the signal handler restart the activity on which you are previously 
        //instead of starting execution from next line. 
     }else { 

      inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s); 
      printf("server : got connection from %s\n", s); 

      //LOGIN  //need to call login function via thread because this 
          //may stop the function if user doesnot respond 
      loginStatus = login_setup(new_fd); 

      //adding to select checkup 
      if(loginStatus) { 
       printf("User Loginned Succesfully\n"); 
      } 
     } 
    } 
    printf("-----------------------------Login Closed. Now starting the QUIZ.-----------------------------\n"); 

    //for randome seek 
    srand(time(NULL)); 

    //for main loop counter 
    int i, win_fd; 

    //for questions 
    int QID = 0; 
    int maxQues_Len = 40, maxOpt_len = 10, maxQuesId_len = 5;//including '\0' this time 
    char quesMsg[80], answer[6];//score doesnot include \0 
    //char ques[40], optA[10], optB[10], optC[10], optD[10]; 

    //for time calculation of each answer 
    ssize_t time_ques, time_ans; 

    //getting all avialable participants 
    fdmax = 0; 
    FD_ZERO(&master); 
    for(i = 0; i < MAX_USERS; i++) { 
     if((new_fd = users[i][1]) != 0){ 
      FD_SET(new_fd, &master); 
      if(new_fd > fdmax) 
       fdmax = new_fd; 
      //printf("%d\n",new_fd); 
     } 
    } 

    int current_rtt; 
    //while for main quiz 
    while(totalQues--) { 

     //checking who are ready for witing 
     if(select(fdmax+1, NULL, &master, NULL, NULL) == -1){//here select will return withh all the descriptors which are 
                   //ready to write , all others have to miss this question 
      perror("select"); 
      exit(1); 
     } 

     //setting which question to send 
     QID++; 

     //for sending questions to all 
     for(i = 0; i <= fdmax; i++) { 
      if(FD_ISSET(i, &master)) { 
       //rtt check 
       current_rtt = rtt_check(i); 
       if(current_rtt == -2) {//connection closed 
        FD_CLR(i, &master); 
        users_deleteFd(i); 
        continue; 
       } 
       //setting question 
       //nextQues(quesMsg, ques, optA, optB, optC, optD); 
       nextQues(quesMsg, QID); 
       printf("Sending Question QID(%s) fd(%d)\n",quesMsg,i); 
       //send a question 
       time_ques = time(NULL); 
       send_ret = send(i, quesMsg, maxQues_Len + 4 * maxOpt_len + maxQuesId_len, 0); 
       if(send_ret == 0) {//connection closed 
        FD_CLR(i, &master); 
        users_deleteFd(i); 
        continue; 
       } 
       wrongRecv(send_ret, maxQues_Len + 4 * maxOpt_len + maxQuesId_len); 
      } 
     } 

     //ASSUMING Question is send ot all the users at same time  
     //receiving and waiting for answers 
     alarm(MAX_ANSWER_TIME); 
     timer = 1; 
     FD_ZERO(&read_fds); 
     read_fds = master; 
     // unsigned int qq = read_fds.fd_count; 
     // for (int ii = 0; ii < qq; ++ii) 
     // { 
     // printf("%d\n",read_fds.fd_array[i]); 
     // } 
     while(timer) { 
      //printf("HURRAY\n"); 
      if(select(fdmax+1, &read_fds, NULL, NULL, NULL) <=0){ 
       perror("select"); 
       //exit(4); 
       break;//break is important. Explained above 
      } 

      for(i = 0; i <= fdmax; i++) { 
       //printf("Recving answer I(%d)\n",i); 
       if(FD_ISSET(i, &read_fds)) { 
        //receiving answer 
        //TODO if we get answer to wrong ques 
        printf("Recving answer I(%d) fdmax (%d)\n",i,fdmax); 
        recv_ret = recv(i,answer,6,0); 
        time_ans = time(NULL); 
        wrongRecv(recv_ret,6); 
        printf("%s\n",answer); 
        if(recv_ret == 0)//connection closed 
        { 
         FD_CLR(i, &read_fds); 
         FD_CLR(i, &master); 
         users_deleteFd(i); 
         continue; 
        }else if(recv_ret > 0){ 
         if(QID == atoi(answer)) { //we have received the answer to this question so remove the user from wait answer loop 
          FD_CLR(i, &read_fds); 
          //printf("%s i(%d)\n","#######",i); 
          answerCheck(i ,answer, current_rtt, (int) difftime(time_ans,time_ques)); 
          //printf("Answer(%c)\n",answer[0]); 
         } 
         else{//we have recvd something unexpectable so ignore for NOW 

         } 
        } 

        //time_t cccc = time(NULL); 
        //printf("%s I(%d)\n",ctime(&cccc),i); 
       } 
      } 
     } 
     //comparing answers 
     win_fd = compareAnswer(); 
     //sending score 
    } 
    return 0; 
} 

클라이언트.C :

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <netdb.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 

#define PORT "3490" //the port client will be connecting to 

#define MAXDATASIZE 100 // max number of bytes we can get at once 

//get sockaddr ,IPv4 or IPv6: 
void *get_in_addr(struct sockaddr *sa) 
{ 
    if(sa->sa_family ==AF_INET) { 
     return &(((struct sockaddr_in*)sa)->sin_addr); 
    } 

    return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 

wrongRecv(ssize_t recvd, ssize_t expctd) 
{ 

    if(recvd != expctd) 
    { 
     printf("Recvd(%zd) bytes not equal to expected(%zd) bytes\n",recvd,expctd); 
     getchar(); 
    } 
} 

void rtt_check(int sockfd) 
{ 
    ssize_t send_ret, recv_ret; 
    char rtt_check[1]; 
    recv_ret = recv(sockfd, rtt_check, 1,0); 
    wrongRecv(recv_ret,1); 
    sleep(1);//to check 
    send_ret = send(sockfd, "r", 1, 0); 
    wrongRecv(send_ret, 1); 

    return; 
} 

int main(int argc, char *argv[]) 
{ 
    int sockfd, numbytes; 
    char buf[MAXDATASIZE]; 
    struct addrinfo hints, *servinfo, *p; 
    int rv; 
    char s[INET6_ADDRSTRLEN]; 

    if(argc != 2) { 
     fprintf(stderr,"usage: client hostname\n"); 
     exit(1); 
    } 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 

    if((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) { 
     fprintf(stderr,"getaddrinfo: %s\n",gai_strerror(rv)); 
     return 1; 
    } 

    //lopp through all the results and connect to the first we can 
    for(p = servinfo; p != NULL; p = p->ai_next) { 
     if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){ 
      perror("client: socket"); 
      continue; 
     } 

     if(connect(sockfd, p->ai_addr, p->ai_addrlen) == -1){ 
      close(sockfd); 
      perror("client: connect"); 
      continue; 
     } 

     break; 
    } 

    if(p ==NULL) { 
     fprintf(stderr,"client: failed to connect\n"); 
     return 2; 
    } 

    inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s); 
    printf("client : connecting to %s\n", s); 

    freeaddrinfo(servinfo); // all done with this structure 
    char login_det[17] = "abhishekabhishek"; 
    char login_retMsg[7], login_stat[3], totalQuesMsg[5]; 
    int totalQues; 

    //sending login details 
    ssize_t send_ret,recv_ret; 
    send_ret = send(sockfd, login_det,16,0); 
    wrongRecv(send_ret,16); 

    //receiving login status 
    recv_ret = recv(sockfd,login_retMsg,7,0); 
    wrongRecv(recv_ret,7); 

    strncpy(login_stat, login_retMsg, 2); 
    login_stat[2] = '\0'; 
    printf("Login Status(%s)\n",login_stat); 
    strncpy(totalQuesMsg, login_retMsg + 2, 5); 
    totalQues = atoi(totalQuesMsg); 
    printf("totalQues(%d)\n",totalQues); 

    if(!strcmp(login_stat,"OK")) { //login ok 
     char quesId[5]; 
     int maxQues_Len = 40, maxOpt_len = 10, maxQuesId_len = 5;//including '\0' this time 
     char quesMsg[80], scoreMsg[1];//score doesnot include \0 
     char ques[40], optA[10], optB[10], optC[10], optD[10]; 
     char answer[6]; 

     while(totalQues--) { 
      //checking rtt 
      rtt_check(sockfd); 
      //receving question 
      recv_ret = recv(sockfd, quesMsg, maxQues_Len + 4 * maxOpt_len + maxQuesId_len ,0); 
      wrongRecv(recv_ret, maxQues_Len + 4 * maxOpt_len + maxQuesId_len); 
      strncpy(quesId,quesMsg,5); 
      strncpy(ques, quesMsg + 05, 40); 
      strncpy(optA, quesMsg + 45, 10); 
      strncpy(optB, quesMsg + 55, 10); 
      strncpy(optC, quesMsg + 65, 10); 
      strncpy(optD, quesMsg + 75, 10); 
      printf("QUESID(%s) Question(%s), A(%s) , B(%s) , C(%s) , D(%s)\n", quesId, ques, optA, optB, optC, optD); 

      //choose answer 
      scoreMsg[0] = 'B'; 

      strncpy(answer,quesId, 5); 
      answer[5] = scoreMsg[0]; 
      sleep(5); 

      //sending answer 
      send_ret = send(sockfd, answer,6,0); 
      wrongRecv(send_ret,6); 
      printf("%s\n","Answer Message Sent"); 


      // if((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) { 
      // perror("recv"); 
      // exit(1); 
      // } 

      // buf[numbytes] = '\0'; 

      // printf("client: received '%s'\n",buf); 
     } 
    } 
    //TODO wrong login 
    close(sockfd); 
    return 0; 
} 

답변

2

문제는 답변을 받고 루프에서 select에 대한 호출이 응답하는 첫 번째 클라이언트 (들)의 바로 파일 기술자를 개최 read_fds을 수정된다는 것이다. 다시 select을 호출하기 전에 read_fds을 재설정하지 않으므로 다른 클라이언트의 응답을 인식하지 못합니다.

+0

아니요, 선택을 다시 호출하고 agian입니다. (각각의 for 루프 선택이 시간까지 다시 호출 된 후). 또한 첫 번째 답변을받은 후 코드를 실행하면 시간까지 선택에서 프로그램이 차단되므로 이는 선택을 다시 호출하고 있음을 의미합니다. –

+0

@knoxxs, 선택을 다시 부릅니다. 문제는 두 번째로 호출 될 때 read_fds의 값입니다. 나는 이것이 숙제 과제이기 때문에 필요한 정확한 변화를 포기하지 않는 것을 선호한다. –

+0

나는 그것을 얻지 못한다. read_fds를 탐색 할 수있는 방법이 있습니까? 검색했지만 찾지 못했습니다. H.W. 할당 문제. 과제 제출 시간이 끝났습니다. 나 자신을 요구하고 있습니다. 하지만 당신이 지적했듯이 나는 첫 번째 대답을받은 후에'read_fds '에 대한 파일 디스크립터만을 삭제할 것이라고 생각한다. 그리고'master '로부터 복사 한 것처럼, 여전히 다른 연결의 파일 기술자를 포함합니다. –