J'utilise send() à la place write() qui ne gère aucun signal :
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 programmation de socket peut être assez délicate, car vous ne savez souvent qu'une erreur s'est produite que bien plus tard.
Par exemple, si la machine sur laquelle vous écrivez s'arrête anormalement, l'appel d'écriture peut réussir (car vous avez pu écrire dans les tampons internes de votre système d'exploitation), mais échouer lors de l'appel de fermeture.
À moins que vous ne disposiez d'un moyen de couche application pour vérifier que le socket est actif (c'est-à-dire envoyer un message et exiger une réponse dans un certain délai), vous n'avez aucun moyen de le savoir. Si vous utilisez un protocole standard, quelque chose existe peut-être déjà pour gérer les erreurs.
Donc, la réponse courte est que vous devez vérifier les retours d'erreur de presque tous les appels qui touchent le socket ( lecture, écriture, fermeture, etc... ).
La façon de vérifier si vous pouvez écrire sur un socket est, étonnamment, d'essayer d'y écrire :-)
Si le socket a été fermé, vous obtiendrez un -1
code de retour de write
et vous pouvez examiner errno
pour voir quel était le problème.
Si le socket est toujours valide mais que vous ne pouvez pas écrire de données pour le moment, write
renverra 0. Le read
call se comporte également de la même manière, renvoyant -1
en cas de problème.
En gros, pour write
:
- si vous récupérez un
-1
, il y a eu un problème et vous devriez vérifiererrno
pour voir s'il est récupérable ou fatal. - Si vous récupérez un
0
, alors vous ne pouvez rien écrire pour le moment (peut-être un backlog réseau ou un autre problème mais certainement pas (encore) fatal). - Si vous obtenez une valeur inférieure à ce que vous vouliez, alors certains des données ont été envoyées. Ajustez vos pointeurs pour pouvoir essayer d'envoyer le reste au cycle suivant. Ne pas supposons qu'une valeur de retour positive signifie que le bloc entier a été envoyé.
- Si vous récupérez le même nombre que le nombre d'octets que vous avez essayé d'envoyer, le tampon entier a été accepté pour livraison.
- Si vous recevez plus que ce que vous avez demandé, envoyez un e-mail aux développeurs du noyau avec un commentaire acerbe. Linus et al vont adorer ça :-)
Mettre à jour : Comme caf l'a souligné dans les commentaires, j'ai oublié de prendre en compte la gestion du signal. Vous devez ignorer le signal de tuyau cassé ou write
échouera en interne en élevant ce signal.
Vous pouvez le faire en insérant :
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);
avant de commencer à utiliser les fonctions de socket. Vous pouvez ensuite utiliser :
sigaction (SIGPIPE, &old_actn, NULL);
pour restaurer le traitement du signal précédent.