select()总是返回1; TCP连接套接字在c ++中出现问题

时间:2011-01-25 07:34:07

标签: c++ sockets select pthreads

我正在做一个c ++项目,它需要服务器创建一个新线程来处理连接,每次accept()返回一个新的套接字描述符。我使用select来决定何时发生连接尝试以及客户端通过新创建的客户端套接字(接受创建的客户端套接字)发送数据的时间。所以有两个函数和两个选择 - 一个用于轮询专用于侦听连接的套接字,一个用于轮询在新连接成功时创建的套接字。

第一种情况的行为是我所期望的 - FD_ISSET仅在请求连接时为我的侦听套接字的id返回true,并且在下次连接尝试之前为false。第二种情况不起作用,即使代码与不同的fd_set和套接字对象完全相同。我想知道这是否源于TCP套接字?由于它们的流动特性,这些套接字在被select选中时总是返回true吗?

//working snippet

struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 500000;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sid,&readfds);

//start server loop
for(;;){

    //check if listening socket has any client requrests, timeout at 500 ms
    int numsockets = select(sid+1,&readfds,NULL,NULL,&tv);
    if(numsockets == -1){
        if(errno == 4){
            printf("SIGINT recieved in select\n");
            FD_ZERO(&readfds);
            myhandler(SIGINT);
        }else{
            perror("server select");
            exit(1);
        }
    }

    //check if listening socket is ready to be read after select returns
    if(FD_ISSET(sid, &readfds)){
        int newsocketfd = accept(sid, (struct sockaddr*)&client_addr, &addrsize);
        if(newsocketfd == -1){
            if(errno == 4){
                printf("SIGINT recieved in accept\n");
                myhandler(SIGINT);
            }else{
                perror("server accept");
                exit(1);
            }
        }else{
            s->forkThreadForClient(newsocketfd);
        }
    } 






//non working snippet

//setup clients socket with select functionality
struct timeval ctv;
ctv.tv_sec = 0;
ctv.tv_usec = 500000;
fd_set creadfds;
FD_ZERO(&creadfds);
FD_SET(csid,&creadfds);



for(;;){

    //check if listening socket has any client requrests, timeout at 500 ms
    int numsockets = select(csid+1,&creadfds,NULL,NULL,&ctv);
    if(numsockets == -1){
        if(errno == 4){
            printf("SIGINT recieved in client select\n");
            FD_ZERO(&creadfds);
            myhandler(SIGINT);
        }else{
            perror("server select");
            exit(1);
        }
    }else{
        printf("Select returned %i\n",numsockets);
    }

    if(FD_ISSET(csid,&creadfds)){


        //read header
        unsigned char header[11];
        for(int i=0;i<11;i++){
            if(recv(csid, rubyte, 1, 0) != 0){
                printf("Received %X from client\n",*rubyte);
                header[i] = *rubyte;
            }
        }

任何帮助都将不胜感激。


感谢您的回复,但我不相信它在循环内部有超时值。我测试了它,即使重置电视并且每次服务器循环时fd_set都归零,select仍然立即返回1。我觉得选择如何处理我的TCP套接字存在问题。每当我设置选择最高套接字ID以包含我的TCP套接字时,它立即返回该套接字集。此外,客户端不发送任何内容,只是连接。

2 个答案:

答案 0 :(得分:6)

必须做的一件事是,每次拨打tv之前,都会将select()的值重置为所需的超时时间。 select()函数更改tv中的值,以指示从函数返回后超时中剩余的时间。如果您未能执行此操作,则select()调用将以超时为零结束,这效率不高。

其他一些操作系统以不同方式实现select(),因为它们不会更改tv的值。 Linux确实会改变它,所以你必须重置它。

答案 1 :(得分:3)

移动

 FD_ZERO(&creadfds); 
 FD_SET(csid,&creadfds); 

进入循环。函数select()报告此结构中的结果。您已使用

检索结果
FD_ISSET(csid,&creadfds);