Réglage du délai d’expiration pour la programmation de la prise tcp de la fonction connect () en C pause recv ()

Dans mon programme Si le serveur n’est pas accessible, la fonction de connexion prend trop de temps. Donc, j’essaie de donner le temps de se connecter en utilisant select (). Maintenant, le problème est que lorsque j’essaie de recevoir des données du serveur en utilisant recvfrom (), j’ai l’erreur “EAGAIN”. Voici le code utilisé pour se connecter et recevoir des données du serveur.

int sock; struct sockaddr_in addr; int connectWithServer { int status; struct timeval timeout; timeout.tv_sec = 10; timeout.tv_usec = 0; addr.sin_port = htons(port); sock = socket (AF_INET,SOCK_STREAM,0); inet_pton(AF_INET,serverIP,&addr.sin_addr); fd_set set; FD_ZERO(&set); FD_SET(sock, &set); fcntl(sock, F_SETFL, O_NONBLOCK); if ( (status = connect(sock, (struct sockaddr*)&addr, sizeof(addr))) == -1) { if ( errno != EINPROGRESS ) return status; } status = select(sock+1, NULL, &set, NULL, &timeout); return status; } long int receiveResponse (void *response , unsigned int length) { socklen_t sockLen = sizeof(struct sockaddr); long int received = recvfrom(sock, response, length, 0,(struct sockaddr *)&addr, &sockLen); printf("Received %ld bytes... err %d\n",received, errno); return received; } 

Réglage du délai d’expiration pour la fonction connect () La programmation de la prise TCP en C ne fonctionne pas

Correction. La définition du délai de connexion fonctionne. Ce qui ne fonctionne pas, c’est la recvfrom() , parce que vous avez laissé le socket en mode non bloquant et que vous ne savez pas quoi faire avec le résultat EAGAIN. Donc, soit gérer cela, en utilisant select() pour vous dire quand le socket est prêt à lire, ou bien remettre le socket en mode blocage après avoir terminé la connexion.

La première sélection réussie signifie que l’opération de connexion est terminée mais ne signifie pas nécessairement qu’elle aboutit . À partir de la page de manuel de connexion , vous devez vérifier SO_ERROR pour vous assurer qu’elle a abouti.

Il est possible de sélectionner (2) ou d’interrogation (2) à compléter en sélectionnant le socket pour l’écriture. Après que select (2) indique qu’il est inscriptible, utilisez getsockopt (2) pour lire l’option SO_ERROR au niveau SOL_SOCKET afin de déterminer si connect () s’est terminé avec succès (SO_ERROR est égal à zéro) ou a échoué (SO_ERROR est l’un des codes d’erreur habituels répertoriés ici, expliquant le résultat. raison de l’échec).

Donc, dans votre code, vous devriez faire quelque chose comme ça:

 int ret; ret=select(sockfd+1, NULL, &wfds, NULL, NULL); //should use timeout if(ret==1 && getSocketOpt(sockfd, SO_ERROR) ==0) { return 0; //successfully connected } 

Ensuite, comme mentionné dans l’autre réponse, vous devez appeler à nouveau Select avant d’écrire ou de lire sur le socket.

Vous recevez EAGAIN car il n’ya pas de données à lire à partir du tampon de socket et votre socket a été définie comme non nonblocking . Puisque vous n’êtes pas connecté avec le pair, je ne suis pas surpris par cela.

Regardez ceci de l’ man recvfrom :

Si aucun message n’est disponible sur le socket, les appels reçus attendent l’arrivée d’un message, sauf si le socket est non bloquant (voir fcntl (2)), auquel cas la valeur -1 est renvoyée et la variable externe errno errno définie sur EAGAIN. Les appels reçus reçoivent normalement toutes les données disponibles, dans la limite du montant demandé, plutôt que d’attendre la réception du montant total demandé.

Un autre cas pourrait être le suivant:

  • Votre socket est peut-être connecté, mais vous vérifiez trop rapidement si quelque chose est reçu. Pour éviter cela, placez une autre sélection avant recvfrom afin d’extraire le paquet de la mémoire tampon du socket (appelant readfrom ou juste en read ) uniquement lorsque vous êtes certain de recevoir quelque chose.

Le socket doit être à nouveau bloqué avant d’appeler recv ().

 fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) & ~O_NONBLOCK);