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

È stato utile?

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top