2013-07-21 24 views
9

Desidero creare una connessione non bloccante. Ti piace questa:Linux, socket, connessione non bloccante

socket.connect(); // returns immediately 

Per questo, io uso un altro thread, un ciclo infinito e epoll Linux. Ti piace questa (pseudocodice):

// in another thread 
{ 
    create_non_block_socket(); 
    connect(); 

    epoll_create(); 
    epoll_ctl(); // subscribe socket to all events 
    while (true) 
    { 
    epoll_wait(); // wait a small time(~100 ms) 
    check_socket(); // check on EPOLLOUT event 
    } 
} 

Se corro un server e un client poi, tutto funziona. Se prima eseguo un client, attendo un po 'di tempo, esegui un server, quindi il client non si connette.

Cosa sto sbagliando? Forse può essere fatto in modo diverso?

+0

Se si sta sollevando un altro thread per eseguire la connessione, perché lo si sta facendo in modo asincrono? Inoltre, potrebbe anche mettere il resto delle comunicazioni in là. –

+0

Bene, come si fa senza epoll e nonblocking? Se chiamo connect(), allora bloccherà e aspetterò la connessione (ho ragione?). Ma poi se voglio unire questo thread di collegamento al thread principale, non posso farlo, perché il thread di collegamento sarà in stato di blocco. Scusa se sbaglio. – herolover

+1

Questo non è 'asincrono'. Questo è non-bloccante. – EJP

risposta

28

Si consiglia di utilizzare i seguenti passi per un asincrona collegare:

  • creare il socket con socket(..., SOCK_NONBLOCK, ...)
  • collegamento dall'inizio con connect(fd, ...)
  • se il valore di ritorno non è né 0EINPROGRESS, quindi interrompere con l'errore
  • attendere che fd sia segnalato come pronto per l'uscita
  • tus di presa con getsockopt(fd, SOL_SOCKET, SO_ERROR, ...)
  • fatto

Nessun loop - a meno che non si desidera gestire EINTR.

Se il client viene avviato per la prima volta, si dovrebbe vedere l'errore ECONNREFUSED nell'ultimo passaggio. Se ciò accade, chiudi lo zoccolo e ricomincia dall'inizio.

È difficile capire cosa c'è che non va nel codice, senza visualizzare ulteriori dettagli. Suppongo che tu non abortire su errori nella tua operazione check_socket.

+0

So che questo è un vecchio commento, ma volevo solo notare che ho dovuto aspettare per leggere per catturare ETIMEDOUT. Ciò si è verificato quando la risposta SYN non è stata restituita. Se avessi solo aspettato la scrittura, il socket sarebbe scomparso da netstat (dallo stato SYN_SENT) ma non avrei ricevuto alcuna notifica che il socket fosse scrivibile per chiamare getsockopt e trovare ETIMEDOUT. Ho anche aggiunto una chiamata subito dopo la connessione a getsockopt per vedere se c'erano degli errori immediati disponibili prima del polling. – DreamWarrior

+0

@DreamWarrior: È strano. Dai un'occhiata a [connect (2)] (http://linux.die.net/man/2/connect) e [connect (3)] (http://linux.die.net/man/3/connect) e cerca 'poll'. Entrambe le pagine man indicano che è necessario attendere l'indicazione, che _socket_ è _writable_. Puoi dare un esempio minimale, che mostra il comportamento inaspettato? – nosid

+0

la pagina man recita "È possibile selezionare (2) o sondare (2) per il completamento selezionando il socket per la scrittura". La mia ipotesi è che la parola chiave sia "completamento". Dal momento che non è mai stato completato, poiché non ha mai ricevuto un SYN-ACK (o RST che completa l'handshake, ma ha esito negativo), non è mai diventato scrivibile. – DreamWarrior