select () всегда возвращает 1; Проблемы с TCP-сокетом в c ++ - PullRequest
4 голосов
/ 25 января 2011

Я делаю проект на C ++, который требует от сервера создания нового потока для обработки соединений каждый раз, когда accept () возвращает новый дескриптор сокета. Я использую команду select, чтобы решить, когда была предпринята попытка подключения, а также когда клиент отправил данные через вновь созданный клиентский сокет (который создает тот, который принимает accept). Таким образом, две функции и два выбора - один для опроса сокета, предназначенного для прослушивания соединений, один для опроса сокета, созданного при успешном новом соединении.

Поведение первого случая соответствует ожидаемому: FD_ISSET возвращает true для идентификатора моего прослушивающего сокета только при запросе соединения и ложно до следующей попытки подключения. Второй случай не работает, хотя код точно такой же с разными объектами fd_set и socket. Мне интересно, это происходит из-за сокета TCP? Всегда ли эти сокеты возвращают значение 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 сразу. Я чувствую, что есть проблема с тем, как select обрабатывает мой TCP-сокет. Каждый раз, когда я устанавливаю, выбирает самый высокий идентификатор сокета, чтобы охватить мой TCP-сокет, он немедленно возвращается с этим набором сокетов. Также клиент ничего не отправляет, просто подключается.

Ответы [ 2 ]

6 голосов
/ 25 января 2011

Одна вещь, которую вы должны сделать, это сбросить значение tv на желаемое время ожидания каждый раз, перед тем как позвонить select(). Функция select() изменяет значения в tv, чтобы указать, сколько времени осталось на тайм-аут после возврата из функции. Если вы этого не сделаете, ваши select() вызовы будут заканчиваться использованием тайм-аута, равного нулю, что неэффективно.

Некоторые другие операционные системы реализуют select() по-другому, таким образом, что они не изменяют значение tv. Linux меняет его, поэтому вы должны сбросить его.

3 голосов
/ 25 января 2011

Переместить

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

в цикл.Функция select() сообщает результат в этой структуре.Вы уже получаете результат с

FD_ISSET(csid,&creadfds);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...