C:部分代码不在select()下执行

时间:2010-02-03 01:46:17

标签: c select timer

我有这样的事情:

#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;

    }

我原本期望在执行期间每隔至少打印一次“Timer elapsed”行(TimeConnected初始化为if条件之一),但由于某种原因,它永远不会打印出来。我以为我的while循环应该继续打印它......任何人都知道我是否在某处乱搞?

编辑: 实际上,我正在使用计时器断开超时后的时间。我刚观察到,如果另一个客户端连接到服务器,它会打印“Timer elapsed”。我确实传递了最后一个参数来进行选择,但我不确定为什么它没有任何效果。

感谢bdk !!如果你有兴趣知道我在这段代码中遇到的“愚蠢”错误,请详细阅读下面的讨论......这是一个明显的错误,我忽略了...因为教程中有一句话:“select modifies你原来的描述符“。

更改列表:

  • 请注意,在while循环中错误地放置了一组FD_ZERO语句
  • FD_ISSET正在传递readfds和writefds而不是tempreadfds和tempwritefds ......

工作代码:

#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;

    }

3 个答案:

答案 0 :(得分:1)

看看你的选择循环参数,它们看起来很腥。主要是你在tempreadfd和tempwritefd上调用select,但是当你调用FD_ISSET时,你传递readfd和writefd。在调用select之前,您正在使用FD_SET来设置您感兴趣的所有fd。由于这些变量未被发送到select,因此未触发的fds不会被屏蔽。因此,您将在所有描述符上检测到“活动”。该接受描述符上确实没有任何活动,因此它会阻塞,直到新客户端连接。

至少我的猜测。

答案 1 :(得分:1)

如果我正在读你的代码,你输入你的while循环,然后检查描述符是否在读集中。如果是,则转到if语句的accept()部分。如果不是,则输入else部分,在此处立即阻止读取。如果套接字处于活动状态,则机器人没有可用的数据,您将阻塞该数据,直到数据可用。它不会进入甚至检查定时器的部分,直到它成功读取或输入错误为止。

如果select返回大于零的值,则只应输入检查套接字的代码,然后在尝试读取套接字之前,应检查套接字是否在读取集中。

通常你会构建一个fdset来检查你接受连接的套接字,另一个用于你接受并正在读取数据的套接字。我想你可以按照你提出的方式做到,但我建议你从read()切换到recv()并使用MSG_PEEK标志。

答案 2 :(得分:0)

这是一个特定于代码的问题,但是谁知道......也许这对其他人有所帮助..我最终使用一个线程来解决问题(我知道......不是最好但我是只是疯了试图调试这个...)。感谢所有有耐心帮助我的人......

在上面的代码中,我没有在main()的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在他的一个答案中提出的原因是程序在接受时阻塞的原因然后,如果它阻塞那里,我将无法计算超时...所以我最终使用一个线程来做这个任务......