2009-05-14 10 views
10

Ecco una versione semplificata di un certo codice su cui sto lavorando:Se una recv non bloccante con MSG_PEEK ha esito positivo, verrà eseguita anche una successiva recv senza MSG_PEEK?

void 
stuff(int fd) 
{ 
    int ret1, ret2; 
    char buffer[32]; 

    ret1 = recv(fd, buffer, 32, MSG_PEEK | MSG_DONTWAIT); 

    /* Error handling -- and EAGAIN handling -- would go here. Bail if 
     necessary. Otherwise, keep going. */ 

    /* Can this call to recv fail, setting errno to EAGAIN? */ 
    ret2 = recv(fd, buffer, ret1, 0); 
} 

Se assumiamo che la prima chiamata a recv riesce, restituendo un valore compreso tra 1 e 32, è sicuro supporre che la seconda chiamata riuscirà anche? Ret2 può essere mai inferiore a ret1? In quali casi?

(Per maggiore chiarezza, si supponga che non ci siano altre condizioni di errore durante la seconda chiamata a recv: che nessun segnale viene consegnato, che non imposterà ENOMEM, ecc. Si supponga inoltre che nessun altro thread guarderà a fd .

sono su Linux, ma MSG_DONTWAIT è, credo, l'unica cosa specifico per Linux qui. si supponga che la fnctl destra è stato impostato in precedenza su altre piattaforme.)

risposta

1

io non sono sicuro di EAGAIN , ma pensa che EBADF o ECONNRESET siano possibili.

+0

'EBADF' non è possibile a meno che un altro thread non chiuda' fd' tra le due chiamate a 'recv'. – pts

7

Lo standard POSIX specifica che con MSG_PEEK "i dati vengono considerati come non letti e la funzione recv() successiva o simile restituirà comunque questi dati". Ciò sembra significare che se ret2 non è -1, sarà uguale a ret1.

5

È inoltre necessario considerare la possibilità che una chiamata recv diversa, su un thread diverso, possa essere chiamata tra ret1 e ret2. L'altra chiamata otterrebbe i tuoi dati, lasciando ret2 a finire senza dati o inaspettatamente meno dati.

Se l'app non è multi-thread o è progettata in modo che il fd venga utilizzato solo da queste due chiamate, è possibile ignorarlo. Ma se questo è un rischio, allora dovresti mettere le due chiamate all'interno di un meccanismo di blocco.

+3

Qualcun altro che acquisisce i dati tra queste due chiamate a 'recv' è possibile anche con programmi a thread singolo: un altro processo con lo stesso descrittore di file socket aperto potrebbe prelevare i dati. Un gestore di segnale nello stesso processo potrebbe anche prendere i dati. (Fortunatamente i gestori di segnale del tuo codice sono solitamente facili da controllare). – pts

0

Per il tuo caso semplice, il successivo recv restituirà il numero di byte ret1 (se ret1 non era un errore). Tuttavia, per la progettazione multi-thread, potrebbe non essere sempre vero.

2

La seconda chiamata a recv() senza MSG_PEEK può fallire con EINTR o restituire dati incompleti perché è stata interrotta da un segnale.

Problemi correlati