2009-11-25 8 views
7

Dans la programmation socket sous Linux, j'ai besoin d'écrire des données dans le socket, mais je ne sais pas socket est ouvert ou fermé. comment je sais que socket est ouvert et ferme sans lire? Je lis à partir de sockfd et je suis sûr que cette connexion est ouverte. Quand écrire un tampon dans newsockfd je ne sais pas newsockfd est ouvert ou fermé comment vérifier newsockfd est fermé?Vérifier la connexion ouverte ou fermée? (En C sous Linux)


Je sais problème. au milieu de la connexion d'écriture fermée. par exemple, écrivez 1024 données dans 500 connexions fermées et programme fermé. comment éviter cela?

Répondre

11

J'utilise send() écrire à la place() qui gèrent 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; 
} 
+0

Cela fonctionnera, et l'autre alternative est d'utiliser 'sigaction' pour ignorer' SIGPIPE' (mettre son gestionnaire à 'SIG_IGN'). – caf

15

La façon de vérifier si vous pouvez écrire sur un socket est, de façon surprenante, d'essayer et écrire :-) il

Si la prise a été fermée, vous obtiendrez un code -1 de retour de write et vous peut examiner errno pour voir quel était le problème.

Si la prise est toujours valide, mais vous ne pouvez pas écrire des données au moment, write renverra 0. L'appel read se comporte aussi de la même façon, le retour -1 s'il y a un problème.

En gros, pour write:

  • si vous revenez un -1, il y a eu un problème et vous devriez vérifier errno pour voir si elle est récupérable ou fatale.
  • Si vous obtenez un 0, vous ne pouvez rien écrire pour le moment (il peut s'agir d'un backlog réseau ou d'un autre problème mais certainement pas (encore) fatal).
  • Si vous obtenez une valeur moins que ce que vous vouliez, alors certains ont été envoyés. Ajustez vos pointeurs afin que vous puissiez essayer d'envoyer le reste au prochain cycle. Ne pas supposer une valeur de retour positive signifie que le bloc entier a été envoyé.
  • Si vous obtenez le même nombre d'octets que vous avez essayé d'envoyer, le tampon entier a été accepté pour livraison.
  • Si vous obtenez plus que ce que vous avez demandé à envoyer, envoyez un email aux développeurs du noyau avec un commentaire acerbe. Linus et al adorera que :-)

Mise à jour: Comme l'a souligné la CAF dans les commentaires, j'ai oublié de prendre en compte le traitement du signal. Vous devez ignorer le signal de tuyau cassé ou write échouera en interne en augmentant 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 la gestion du signal précédent.

+0

dans la ligne suivante si (n <= 0), mais en fonction d'écriture une erreur est survenue et programme près – SjB

+0

@SjB, Ne pas * assumer * les problèmes si 'write' renvoie 0. Cela peut arriver s'il y a un backlog réseau temporaire. Si l'arriéré se transforme en un réel problème, la session sera arrêtée et vous obtiendrez -1. Jusque-là, continuez d'essayer. – paxdiablo

+0

Je connais un problème. au milieu de la connexion d'écriture fermée. par exemple écrire 1024 données dans 500 connexions fermées et le programme fermé – SjB

4

La programmation de sockets peut être plutôt difficile, car vous ne savez souvent pas qu'une erreur est survenue bien plus tard.Par exemple, si la machine que vous écrivez pour s'arrêter anormalement, l'appel d'écriture peut réussir (car vous étiez en mesure d'écrire dans vos tampons d'OS internes), pour échouer pendant l'appel de fermeture.

À moins que vous n'ayez une méthode de vérification de l'application de la couche application (c'est-à-dire, l'envoi d'un message et nécessitant une réponse dans un certain délai), vous n'avez aucun moyen de le savoir. Si vous utilisez un protocole standard, quelque chose peut déjà exister 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 (lire, écrire, fermer, etc ...).

+2

Malheureusement, c'est la bonne réponse. J'ai essayé plusieurs façons de savoir si les connexions HTTP persistantes sont toujours valides mais ce n'est pas fiable et sans conditions de course. – Lothar

Questions connexes