irritante comportamento seleccione () em c
Pergunta
while (xxx) {
timeout.tv_sec=TIMEOUT;
timeout.tv_usec=0;
FD_ZERO(&set);
FD_SET(sd,&set);
switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
xxxxx
}
funciona bem, no entanto
FD_ZERO(&set);
FD_SET(sd,&set);
while (xxx) {
timeout.tv_sec=TIMEOUT;
timeout.tv_usec=0;
switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
xxxxx
}
não. Ele funciona da primeira vez, mas da próxima vez que atravessa o loop while fica um tempo limite, mesmo se a tomada de sd recebe dados. Parece-me ser um desperdício de recursos ter que esvaziar e encher definir cada vez.
Alguém tem uma boa explicação por que isso é, e ainda melhor, talvez uma sugestão como evitá-lo?
Solução
selecione modifica seus argumentos. Você realmente tem que reinicializar-lo cada vez.
Se você está preocupado com a sobrecarga, o custo de processamento do fd_set completa no kernel é um pouco mais importante do que o custo de FD_ZERO. Você gostaria de passar apenas em sua fd máxima, não FD_SETSZIZE, para minimizar o processamento de kernel. No seu exemplo:
switch (select((sd + 1),&set,NULL,NULL,&timeout))
Para um caso mais complexo, com vários fds, você normalmente acaba mantendo uma variável máx:
FD_SET(sd,&set);
if (sd > max) max = sd;
... repeat many times...
switch (select((max + 1),&set,NULL,NULL,&timeout))
Se você vai ter um grande número de descritores de arquivos e estão preocupados com a sobrecarga de schlepping-los sobre, você deve olhar para algumas das alternativas para selecionar (). Você não menciona o sistema operacional que você está usando, mas para Unix-like sistemas operacionais há alguns:
- para Linux, epoll ()
- para o FreeBSD / NetBSD / OpenBSD / MacOS X, kqueue ()
- para Solaris, / dev / poll
As APIs são diferentes, mas todos eles são essencialmente uma interface de kernel stateful para manter um conjunto de descrições de arquivos ativos. Uma vez que um fd é adicionado ao conjunto, você será notificado sobre os eventos nesse fd sem ter que continuamente passá-lo novamente.
Outras dicas
Leia a página man select. O conjunto retornado apenas os descritores de arquivos que estão prontos para ser usados. Você é suposto para usar FD_ISSET para verificar cada um, se ele é definido ou não.
Sempre inicializar o direito fd_set antes de usá-lo.
Essa é a maneira trabalhos seletos. Ele funciona melhor e faz mais sentido, se você tiver mais de um soquete. Isso é uma espécie de ponto: você está selecionando através de muitos sockets. Se você quiser ler a partir de uma tomada, basta ler ou recv-lo.