Witam. Od dość długiego czasu szukam odpowiedzi na nękający mnie... brak wiedzy. Szukałem odpowiedzi w manualach, na forach dyskusyjnych, ircu czy nawet ostatnio skłoniłem się do wybiórczego przejrzenia książki nt. programowania sieciowego (Richarda Stevensa). Niestety...
Mój problem dotyczy funkcji select, a dokładniej parametru fd_set *writefds.
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
Jak mówi manual, select kończy działanie kiedy któryś z deskryptorów zbioru writefds jest zdolny do zapisu. W przypadku kiedy deskryptor jest uchwytem połączenia, stan "zdolny do zapisu" występuje prawie zawsze. W efekcie, select bez opamiętania kończy działanie, a pętla w której ów select jest, kręci się w kółko zabijając procesor. Oczywiście takie zachowanie jest poprawne.
// Jakiś poprawnie otwarty socket...
FD_SET(foo_client,&fdswrite);
for(;;) {
result = select(nfds+1,NULL,&fdswrite,NULL,NULL);
if(FD_ISSET(foo_client,&fdswrite))
printf("Zabijamy procesor...\r\n");
}
Tylko takie zachowanie w przypadku serwera nie ma najmniejszego sensu. Dlatego, jeżeli by się przyjęło, taką zasadę, że zbiór fdswrite zawiera tylko te deskryptory na które chce pisać serwer (zachodzi potrzeba wysłania danych? dodajemy deskryptor do fdswrite), a gdy to uczyni deskryptor zostaje usunięty z listy. Takie rozwiązanie było by wydajne, oraz nie zabijało by procesora.
// Jakiś poprawnie otwarty socket...
FD_SET(foo_client,&fdsread);
for(;;) {
result = select(nfds+1,&fdsread,&fdswrite,NULL,NULL);
// Klient coś nam przesłał.
if(FD_ISSET(foo_client,&fdsread)) {
result = recv();
...
// Chcemy odpowiedzieć.
FD_SET(foo_client,&fdswrite);
add_send_buffer(foo_client,"ODPOWIEDZ.");
}
if(FD_ISSET(foo_client,&fdswrite)) {
result = send(...,get_send_buffer(foo_client),...);
...
// Jeżeli wysłano wszystko.
if(send_buffer_sended(foo_client)) {
FD_CLR(foo_client,&fdswrite);
send_buffer_free(foo_client);
}
}
}
Tylko pytanie czy takie rozwiązanie jest poprawne? W dyskusji na ircu (na kanale #4programmers (: ) można było usłyszeć, że takie rozwiązanie jak powyżej jest... niezamierzonym efektem. Niestety argumentów dlaczego, nie mogę tutaj przytoczyć z racji, iż owa rozmowa miała miejsce dość dawno.