Uso send() invece write() che non gestisce alcun segnale :
bzero(buffer, MAX_SIZE_BUFFER);
n = read(sockfd, buffer, MAX_SIZE_BUFFER - 1);
printf("after read%d\n", n);
if (n <= 0)
{
break;
}
n2 = send(newsockfd, buffer, n, MSG_NOSIGNAL);
if (n2 == -1)
{
close(sockfd);
close(newsockfd);
return;
}
if (n2 != n)
{
break;
}
La programmazione dei socket può essere piuttosto complicata, perché spesso non sai che si è verificato un errore se non molto tempo dopo.
Ad esempio, se la macchina su cui stai scrivendo si spegne in modo anomalo, la chiamata di scrittura potrebbe riuscire (poiché sei stato in grado di scrivere nei buffer interni del tuo sistema operativo), solo per fallire durante la chiamata di chiusura.
A meno che tu non abbia un modo a livello di applicazione per verificare che il socket sia attivo (ovvero, inviando un messaggio e richiedendo una risposta entro un certo periodo di tempo) non hai modo di saperlo. Se stai usando un protocollo standard, potrebbe già esistere qualcosa per gestire gli errori.
Quindi la risposta breve è che devi controllare i ritorni di errore praticamente da ogni chiamata che tocca il socket ( leggi, scrivi, chiudi, ecc ... ).
Il modo per verificare se puoi scrivere su un socket è, sorprendentemente, provare a scriverci sopra :-)
Se il socket è stato chiuso, otterrai un -1
codice di ritorno da write
e puoi esaminare errno
per vedere qual era il problema.
Se il socket è ancora valido ma al momento non puoi scrivere alcun dato, write
restituirà 0. Il read
call si comporta anch'essa in modo simile, restituendo -1
se c'è un problema.
Fondamentalmente, per write
:
- se ricevi indietro un
-1
, si è verificato un problema e dovresti selezionareerrno
per vedere se è recuperabile o fatale. - Se ricevi un
0
, quindi non puoi scrivere nulla al momento (potrebbe essere un arretrato di rete o qualche altro problema ma sicuramente non (ancora) fatale). - Se ottieni un valore inferiore a quello che volevi, allora alcuni dei dati è stato inviato. Regola i tuoi puntatori in modo da poter provare a inviare il resto nel ciclo successivo. No assumere un valore di ritorno positivo significa che l'intero blocco è stato inviato.
- Se ricevi lo stesso numero del numero di byte che hai provato a inviare, l'intero buffer è stato accettato per la consegna.
- Se ricevi più di quanto hai chiesto di ricevere, invia un'e-mail agli sviluppatori del kernel con qualche commento aspro. Linus e altri lo adoreranno :-)
Aggiornamento: Come ha sottolineato caf nei commenti, ho dimenticato di prendere in considerazione la gestione del segnale. Devi ignorare il segnale di tubo rotto o write
fallirà internamente alzando quel segnale.
Puoi farlo inserendo:
struct sigaction new_actn, old_actn;
new_actn.sa_handler = SIG_IGN;
sigemptyset (&new_actn.sa_mask);
new_actn.sa_flags = 0;
sigaction (SIGPIPE, &new_actn, &old_actn);
prima di iniziare a utilizzare le funzioni socket. Puoi quindi utilizzare:
sigaction (SIGPIPE, &old_actn, NULL);
per ripristinare la precedente gestione del segnale.