recv avec prise non bloquante

J’essaie d’implémenter un non-blocage pour socket recv et le problème est que j’ai une erreur -1 quand il n’y a pas de données mais je m’attends à avoir une erreur EAGAIN .

Socket est définitivement réglé sur un état non bloquant, j’ai vérifié flags = fcntl(s, F_GETFL, 0) pour le drapeau O_NONBLOCK .

Merci beaucoup d’avance!

 #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #define ETH_FRAME_LEN_MY 1400 void print(void *buf, int length) { int i; for (i = 0; i < length; ++i) putchar(((char *)buf)[i]); printf("\n"); } int main(){ int flags, s, r, err; struct sockaddr_ll socket_addr; char ifName[IFNAMSIZ] = "eth0"; struct ifreq if_idx; struct ifreq if_mac; s = socket(PF_PACKET, SOCK_RAW, htons(0x88b6)); if (s == -1) { perror("socket"); } flags = fcntl(s,F_GETFL,0); assert(flags != -1); fcntl(s, F_SETFL, flags | O_NONBLOCK); flags = fcntl(s, F_GETFL, 0); if ((flags & O_NONBLOCK) == O_NONBLOCK) { printf("it's nonblocking"); } else { printf("it's blocking."); } /* Get the index of the interface to send on */ memset(&if_idx, 0, sizeof(struct ifreq)); strncpy(if_idx.ifr_name, ifName, IFNAMSIZ-1); if (ioctl(s, SIOCGIFINDEX, &if_idx) < 0) {perror("SIOCGIFINDEX");} memset(&socket_addr, 0, sizeof(socket_addr)); socket_addr.sll_ifindex = if_idx.ifr_ifindex; socket_addr.sll_protocol = htons(0x88b5); socket_addr.sll_family = PF_PACKET; socket_addr.sll_pkttype = PACKET_OUTGOING; r = bind(s, (struct sockaddr*)&socket_addr, sizeof(socket_addr)); if ( r < 0) { perror("bind"); } void* buffer = (void*)malloc(ETH_FRAME_LEN_MY); /*Buffer for ethernet frame*/ int length = 0; /*length of the received frame*/ while(1){ printf("1\n"); length = recv(s, buffer, ETH_FRAME_LEN_MY, 0); printf("2\n"); if (length < 0) { if (length == -EAGAIN) printf("non-blocking succeeded\n"); else printf("error code %i\n", length); } //printf ("buffer %s\n", buffer); print(buffer, length); } return 0; } 

Vous devez vérifier errno , pas la longueur, pour connaître la raison pour laquelle le socket n’a pas renvoyé de données. En outre, EWOULDBLOCK est l’autre code d’erreur à vérifier en plus de EAGAIN . Changez votre boucle while comme suit:

 while(1) { int err; printf("1\n"); length = recv(s, buffer, ETH_FRAME_LEN_MY, 0); err = errno; // save off errno, because because the printf statement might reset it printf("2\n"); if (length < 0) { if ((err == EAGAIN) || (err == EWOULDBLOCK)) { printf("non-blocking operation returned EAGAIN or EWOULDBLOCK\n"); } else { printf("recv returned unrecoverable error(errno=%d)\n", err); break; } } //printf ("buffer %s\n", buffer); print(buffer, length); } 

Bien entendu, cette boucle infinie entrera dans un cycle de perte de temps du processeur en attente de données. Il existe plusieurs façons d’être averti de l’arrivée de données sur un socket sans avoir à appeler recv() dans une boucle de rotation. Cela inclut select appels de select et d’ poll .

J’ai une erreur -1 quand il n’y a pas de données mais je m’attends à obtenir une erreur EAGAIN.

-1 vous indique qu’il y a une erreur. errno vous dit quelle était l’erreur.