Come scorrere un fd_set
-
01-10-2019 - |
Domanda
Mi chiedo se c'è un modo semplice per scorrere un fd_set? Il motivo che voglio fare questo è quello di non dover scorrere tutti socket connessi, in quanto altera selezionare () questi fd_sets a solo includono quelli che sono interessato circa. So anche che utilizzando un'implementazione di un tipo che non è destinata ad essere letta direttamente è generalmente una cattiva idea quanto può variare tra i diversi sistemi. Tuttavia, ho bisogno di qualche modo per fare questo, e io sono a corto di idee. Quindi, la mia domanda è:
Come faccio a iterare attraverso un fd_set? Se questa è una pessima pratica, ci sono altri modi per risolvere il mio "problema" se non da loop attraverso tutti i socket connessi?
Grazie
Soluzione
Seleziona imposta il bit corrispondente al descrittore di file nel set, così, è necessario, non scorrere tutti i fds, se siete interessati solo in pochi (e possibile ignorare gli altri) semplicemente testare solo quei file-descrittori per i quali si è interessati.
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
if(FD_ISSET(fd0, &read_fds))
{
//do things
}
if(FD_ISSET(fd1, &read_fds))
{
//do more things
}
Modifica
Ecco l'struct fd_set:
typedef struct fd_set {
u_int fd_count; /* how many are SET? */
SOCKET fd_array[FD_SETSIZE]; /* an array of SOCKETs */
} fd_set;
Dove, fd_count è il numero di socket set (in modo, è possibile aggiungere un'ottimizzazione di utilizzare questo) e fd_array è un vettore di bit (delle dimensioni FD_SETSIZE * sizeof (int) che è dipendente dalla macchina ). Nella mia macchina, è 64 * 64 = 4096.
Quindi, la tua domanda è essenzialmente: qual è il modo più efficace per trovare le posizioni dei bit di 1s in un vettore di bit (di dimensioni di circa 4096 bit)
voglio chiarire una cosa qui:
"Loop attraverso tutti i socket connessi" non vuol dire che in realtà si sta leggendo / fare cose a una connessione. FD_ISSET () solo controlli weather bit nella fd_set posizionato al numero assegnato file_descriptor della connessione è impostata oppure no. Se l'efficienza è il vostro obiettivo, allora non è questo il più efficiente? usando euristiche?
ci dica cosa c'è di sbagliato con questo metodo, e quello che stai cercando di raggiungere con il metodo alternativo.
Altri suggerimenti
Si deve compilare uno struct fd_set prima di chiamare select (), non è possibile passare in std :: originale di prese direttamente. selezionare () modifica le fd_set conseguenza, rimuovendo eventuali prese che non sono "set", e ritorna quante prese sono rimanenti. Bisogna scorrere l'fd_set risultante, non il vostro std :: set. Non c'è bisogno di chiamare FD_ISSET () perché il fd_set risultante contiene solo prese "set" che sono pronti, ad esempio:
fd_set read_fds;
FD_ZERO(&read_fds);
int max_fd = 0;
read_fds.fd_count = connected_sockets.size();
for( int i = 0; i < read_fds.fd_count; ++i )
{
read_fds.fd_array[i] = connected_sockets[i];
if (read_fds.fd_array[i] > max_fd)
max_fd = read_fds.fd_array[i];
}
if (select(max_fd+1, &read_fds, NULL, NULL, NULL) > 0)
{
for( int i = 0; i < read_fds.fd_count; ++i )
do_socket_operation( read_fds.fd_array[i] );
}
Dove FD_ISSET () entra in gioco il più delle volte è quando si utilizza il controllo degli errori con select (), ad esempio:
fd_set read_fds;
FD_ZERO(&read_fds);
fd_set error_fds;
FD_ZERO(&error_fds);
int max_fd = 0;
read_fds.fd_count = connected_sockets.size();
for( int i = 0; i < read_fds.fd_count; ++i )
{
read_fds.fd_array[i] = connected_sockets[i];
if (read_fds.fd_array[i] > max_fd)
max_fd = read_fds.fd_array[i];
}
error_fds.fd_count = read_fds.fd_count;
for( int i = 0; i < read_fds.fd_count; ++i )
{
error_fds.fd_array[i] = read_fds.fd_array[i];
}
if (select(max_fd+1, &read_fds, NULL, &error_fds, NULL) > 0)
{
for( int i = 0; i < read_fds.fd_count; ++i )
{
if( !FD_ISSET(read_fds.fd_array[i], &error_fds) )
do_socket_operation( read_fds.fd_array[i] );
}
for( int i = 0; i < error_fds.fd_count; ++i )
{
do_socket_error( error_fds.fd_array[i] );
}
}
E 'abbastanza straight-forward:
for( int fd = 0; fd < max_fd; fd++ )
if ( FD_ISSET(fd, &my_fd_set) )
do_socket_operation( fd );
Questo loop è una limitazione dell'interfaccia select()
. Le implementazioni sottostanti fd_set
sono di solito un insieme di bit, che significa ovviamente che sta cercando una presa richiede la scansione sui bit.
E 'proprio per questo motivo che diverse interfacce alternative sono state create - purtroppo, sono tutti i sistemi operativi specifici. Ad esempio, Linux fornisce epoll , che restituisce un elenco dei soli descrittori di file che sono attivi. FreeBSD e Mac OS X sia fornire kqueue , che compie lo stesso risultato.
Si veda questa sezione 7.2 di Beej ' s guida al networking - '7.2. select () -. sincrono I / O multiplexing' utilizzando FD_ISSET
In breve, si deve scorrere un fd_set al fine di determinare se il descrittore di file è pronto per la lettura / scrittura ...
Non credo che quello che si sta cercando di fare è una buona idea.
In primo luogo il suo sistema di dipendente, ma credo che già lo sai.
In secondo luogo, a livello interno questi insiemi sono memorizzati come un array di interi e FDS vengono memorizzati come bit impostati. Ora, secondo le pagine man di selezionare il FD_SETSIZE è 1024. Anche se si voleva iterare e ottenere il vostro fd interessati è quello che dovete ciclare su quel numero con il pasticcio di manipolazione dei bit. Quindi, a meno si è in attesa per più di FD_SETSIZE di selezionare su quale io non la penso così è possibile, la sua non è una buona idea fd.
Oh aspetta !!. In ogni caso la sua non è una buona idea.
Non credo che si possa fare molto utilizzando in modo efficiente la chiamata select()
. L'informazione a " Il C10K problema " sono ancora validi.
Si avrà bisogno di alcune soluzioni piattaforma specifiche:
In alternativa è possibile utilizzare una libreria evento per nascondere dettaglio piattaforma per voi libev