2009-05-14 10 views
10

est ici une version simplifiée d'un certain code que je travaille sur:Si une recv non bloquante avec MSG_PEEK réussit, un recv ultérieur sans MSG_PEEK réussira-t-il également?

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); 
} 

Si nous supposons que le premier appel à recv réussit, retourner une valeur comprise entre 1 et 32, est-il raisonnable de supposer que le deuxième appel va également réussir? Est-ce que ret2 peut être moins que ret1? Dans quels cas? Pour des raisons de clarté, supposons qu'il n'y ait pas d'autres conditions d'erreur lors du second appel à recv: qu'aucun signal n'est délivré, qu'il ne définira pas ENOMEM, etc. Supposons également qu'aucun autre thread ne regarde fd .

Je suis sous Linux, mais MSG_DONTWAIT est, je crois, la seule chose spécifique à Linux ici. on suppose que le droit fnctl a été définie auparavant sur d'autres plateformes.)

Répondre

1

Je ne suis pas sûr EAGAIN , mais pense que EBADF ou ECONNRESET sont possibles.

+0

'EBADF' n'est pas possible à moins qu'un autre thread ferme' fd' entre les deux appels à 'recv'. – pts

7

La norme POSIX spécifie qu'avec MSG_PEEK, "les données sont traitées comme non lues et la prochaine fonction recv() ou similaire retournera toujours ces données." Cela semble signifier que si ret2 est -1, ce sera la même chose que ret1.

5

Vous devez également considérer la possibilité qu'un appel recv différent, sur un thread différent, puisse être appelé entre ret1 et ret2. Cet autre appel recevrait vos données, laissant ret2 pour se retrouver sans données, ou de façon inattendue moins de données.

Si votre application n'est pas multithread ou si elle est conçue pour que fd ne soit utilisée que par ces deux appels, vous pouvez ignorer cette situation. Mais si c'est un risque, alors vous devriez mettre les deux appels à l'intérieur d'un mécanisme de verrouillage.

+3

Quelqu'un d'autre saisissant les données entre ces deux appels à 'recv' est possible même avec des programmes à un seul thread: un autre processus avec le même descripteur de fichier socket ouvert peut saisir les données. Un gestionnaire de signal dans le même processus peut également saisir les données. (Heureusement, les gestionnaires de signal dans votre code sont généralement faciles à contrôler.) – pts

0

Pour votre cas simple, le recv suivant renverra ret1 nombre d'octets (si ret1 n'était pas une erreur). Cependant, pour la conception multi-thread, il peut ne pas toujours être vrai.

2

Votre deuxième appel à recv() sans MSG_PEEK peut échouer avec EINTR ou renvoyer des données incomplètes car il a été interrompu par un signal.

Questions connexes