Partage
  • Partager sur Facebook
  • Partager sur Twitter

[socket] faire un timeout

Sujet résolu
    12 mai 2008 à 6:33:41

    Bonjour,

    Je travaille sur un serveur, et j'aimerais qu'il puisse se déconnecter en cas de trop longue attente de reception.

    Mais comme le fonction recv() bloque le programme en attente, aucune condition ne marche...

    Avez vous des idées ?

    Merci
    • Partager sur Facebook
    • Partager sur Twitter
      12 mai 2008 à 6:39:25

      Il faut créer un thread spécifique pour le recv. Le reste n'est qu'un bête timer.
      • Partager sur Facebook
      • Partager sur Twitter
        12 mai 2008 à 7:47:29

        Citation : yoch

        Je travaille sur un serveur, et j'aimerais qu'il puisse se déconnecter en cas de trop longue attente de reception.

        Tu veux dire déconnecter le client ?

        select() est fait pour ça.
        • Partager sur Facebook
        • Partager sur Twitter
        Music only !
          13 mai 2008 à 6:04:48

          Citation : -ed-

          Citation : yoch

          Je travaille sur un serveur, et j'aimerais qu'il puisse se déconnecter en cas de trop longue attente de reception.

          Tu veux dire déconnecter le client ?

          select() est fait pour ça.



          Oui, je veux bel et bien dire déconnecter le client. :)

          J'ai essayé select() de la façon que tu décris sur ta page, mais il me retourne invariablement : error.

          Je suis donc toujours bloqué.

          Mon code (adaptation du tuto sur les sockets) :
          #include <winsock2.h>
          #include <stdio.h>
          #include <stdlib.h>
          #include <pthread.h>
          #include <time.h>
          #define PORT 23
          
          #include "header.h"
          
          int envoi(SOCKET csock, SOCKET sock_err, char buffer[256], int lenght)
          {
              sock_err = send(csock, buffer, lenght, 0);
              if(sock_err != SOCKET_ERROR)
              {
                  printf(">%s", buffer);
              }
              else
              {
                  printf("Erreur de transmission, <<%s>> non transmis\n", buffer);
              }
              return sock_err;
          }
          
          int recois(SOCKET csock, SOCKET sock_err, char reception[256])
          {
              int n;
              n = recv (csock, reception, 256 , 0);
              reception[n] = 0;
              if(sock_err != SOCKET_ERROR)
              {
                  printf ("<%s", reception);
              }
              else
              {
                  printf("Erreur de reception\n");
              }
              return sock_err;
          }
          
          int main(void)
          {
          
              WSADATA WSAData;
              int erreur = WSAStartup(MAKEWORD(2,0), &WSAData);
          
              Server server; /*structure SOCKET et SOCKADDR_IN*/
          
              char buffer[32] = "Bonjour !\n";
              int recsize = (int) sizeof server.csin;
              int sock_err;
          
              /* Si les sockets Windows fonctionnent */
              if(!erreur)
              {
                  server.sock = socket(AF_INET, SOCK_STREAM, 0);
          
                  /* Si la socket est valide */
                  if(server.sock != INVALID_SOCKET)
                  {
                      printf("La socket %d est maintenant ouverte en mode TCP/IP\n", server.sock);
          
                      /* Configuration */
                      server.sin.sin_addr.s_addr    = htonl(INADDR_ANY);   /* Adresse IP automatique */
                      server.sin.sin_family         = AF_INET;             /* Protocole familial (IP) */
                      server.sin.sin_port           = htons(PORT);         /* Listage du port */
                      sock_err = bind(server.sock, (SOCKADDR *) &server.sin, sizeof server.sin);
          
                      /* Si la socket fonctionne */
                      if(sock_err != SOCKET_ERROR)
                      {
                          /* Démarrage de l'ecoute (mode server) */
                          sock_err = listen(server.sock, 5);
                          printf("Ecoute du port %d...\n", PORT);
          
                          /* Si la socket fonctionne */
                          if(sock_err != SOCKET_ERROR)
                          {
                              /* Attente pendant laquelle le client se connecte */
                              printf("Patientez pendant que le client se connecte sur le port %d...\n", PORT);
          
                              server.csock = accept(server.sock, (SOCKADDR *) &server.csin, &recsize);
                              printf("Un client se connecte avec la socket %d de %s:%d\n", server.csock, inet_ntoa(server.csin.sin_addr), htons(server.csin.sin_port));
          
                              while (sock_err != SOCKET_ERROR)
                              {
                                  struct timeval timeout;
                                  timeout.tv_sec = 1; /* 15 s */
                                  int err = select (0, NULL, NULL, NULL, &timeout);
          
                                  switch (err)
                                  {
                                  case 0:
                                      puts ("timeout");
                                      sock_err = SOCKET_ERROR;
                                      break;
                                  case -1:
                                      puts ("error");
                                      sock_err = SOCKET_ERROR;
                                      break;
                                  default:
                                      sock_err = envoi(server.csock, sock_err, buffer, strlen(buffer));
                                      sock_err = recois(server.csock, sock_err, buffer);
                                  }
                              }
                              /* Il ne faut pas oublier de fermer la connexion (fermée dans les deux sens) */
                              shutdown(server.csock, 2);
                          }
                      }
          
                      /* Fermeture de la socket */
                      printf("Fermeture de la socket...\n");
                      closesocket(server.sock);
                      printf("Fermeture du serveur terminee\n");
                  }
                      WSACleanup();
              }
          
              /* On attend que l'utilisateur tape sur une touche, puis on ferme */
              getchar();
          
              return EXIT_SUCCESS;
          }
          
          • Partager sur Facebook
          • Partager sur Twitter
            13 mai 2008 à 9:39:41

            Citation : yoch

            Citation : -ed-

            Citation : yoch

            Je travaille sur un serveur, et j'aimerais qu'il puisse se déconnecter en cas de trop longue attente de reception.

            Tu veux dire déconnecter le client ?

            select() est fait pour ça.



            Oui, je veux bel et bien dire déconnecter le client. :)

            J'ai essayé select() de la façon que tu décris sur ta page, mais il me retourne invariablement : error.

            Je suis donc toujours bloqué.

            Mon code (adaptation du tuto sur les sockets) :



            J'ai reporté les corrections signalées dans ton autre post (threads)...
            struct timeval timeout;
            

            Attention à toujours initialiser les structures.
            struct timeval timeout = {0};
            


            Je ne vois pas ce que tu cherches à faire avec le select() placé ici...

            Tel que tu l'a mis, il attend 1 seconde et fait sortir de la boucle. Quel intérêt ?

            Il faut cesser de coder au hasard et prendre le temps d'étudier les fonctions. select() est puissante, mais complexe.

            http://www.opengroup.org/onlinepubs/00 [...] h/select.html

            select() est une fonction qui peut être bloquante sur 4 types d'attente d'évènements :

            - émission de 1 ou plusieurs sockets
            - réception de données 1 ou plusieurs sockets
            - réception de commandes de 1 ou plusieurs sockets
            - échéance de temps

            Ensuite, il faut réfléchir 5 minutes à ce que doit faire le programme avant de coder...

            Si tu veux tester un timeout 'réponse client', il faut faire comme ceci (en gros) :

            select() doit surveiller 2 évènements :
            - le socket client en réception de données
            - l'échéance de temps

            ; pseudocode
            err = 0
            while (!err)
            {
               ret = select (csock, 30 secondes)
               if (ret == 0)
               {
                  puts ("timeout")
                  err=1;
               }
               else
               if (IS (csock))
               {
                  err = recv()
                  if (!err)
                  {
                     ...
                     err = send()
                  }
               }
            }

            Je te laisse corriger.

            Ceci fonctionne :
            #include <winsock2.h>
            #include <stdio.h>
            #include <stdlib.h>
            #include <pthread.h>
            #include <time.h>
            #define PORT 23
            
            #if 0
            #include "header.h"
            #else
            typedef struct
            {
               /* server */
               SOCKET sock;
               SOCKADDR_IN sin;
            
               /* client */
               SOCKET csock;
               SOCKADDR_IN csin;
            }
            Server;
            
            #endif
            
            int envoi (SOCKET csock, char const *buffer, int length)
            {
               int err = send (csock, buffer, length, 0);
               if (err != SOCKET_ERROR)
               {
                  printf (">%s", buffer);
                  err = 0;
               }
               else
               {
                  printf ("Erreur de transmission, <<%s>> non transmis\n", buffer);
                  err = 1;
               }
               return err;
            }
            
            int recoit (SOCKET csock, char reception[], int taille)
            {
               int err = 0;
               int n = recv (csock, reception, taille - 1, 0);
               if (n > 0)
               {
                  reception[n] = 0;
                  printf ("<%s", reception);
               }
               else if (n < 0)
               {
                  printf ("Erreur de reception\n");
                  err = 1;
               }
               else
               {
                  printf ("Deconnexion\n");
                  err = 1;
               }
               return err;
            }
            
            int main (void)
            {
            
               WSADATA WSAData;
               int erreur = WSAStartup (MAKEWORD (2, 0), &WSAData);
            
               /* Si les sockets Windows fonctionnent */
               if (!erreur)
               {
                  Server server;            /*structure SOCKET et SOCKADDR_IN */
            
                  server.sock = socket (AF_INET, SOCK_STREAM, 0);
            
                  /* Si la socket est valide */
                  if (server.sock != INVALID_SOCKET)
                  {
                     int sock_err;
            
                     printf ("La socket %d est maintenant ouverte en mode TCP/IP\n",
                             server.sock);
            
                     /* Configuration */
                     server.sin.sin_addr.s_addr = htonl (INADDR_ANY); /* Adresse IP automatique */
                     server.sin.sin_family = AF_INET; /* Protocole familial (IP) */
                     server.sin.sin_port = htons (PORT); /* Listage du port */
                     sock_err =
                        bind (server.sock, (SOCKADDR *) & server.sin, sizeof server.sin);
            
                     /* Si la socket fonctionne */
                     if (sock_err != SOCKET_ERROR)
                     {
                        /* Démarrage de l'ecoute (mode server) */
                        sock_err = listen (server.sock, 5);
                        printf ("Ecoute du port %d...\n", PORT);
            
                        /* Si la socket fonctionne */
                        if (sock_err != SOCKET_ERROR)
                        {
                           int recsize = (int) sizeof server.csin;
            /* Attente pendant laquelle le client se connecte */
                           printf
                              ("Patientez pendant que le client se connecte sur le port %d...\n",
                               PORT);
            
                           server.csock =
                              accept (server.sock, (SOCKADDR *) & server.csin, &recsize);
                           printf ("Un client se connecte avec la socket %d de %s:%d\n",
                                   server.csock, inet_ntoa (server.csin.sin_addr),
                                   htons (server.csin.sin_port));
            
                           /* message d'accueil */
                           {
                              char const *hello = "Bonjour !\n";
                              sock_err = envoi (server.csock, hello, strlen (hello));
                           }
            
                           /* attente de la reponse du client (max 15 secondes) */
                           {
                              int err;
                              do
                              {
                                 fd_set readfs;
                                 struct timeval timeout = { 0 };
            
                                 FD_ZERO (&readfs); /* clears readfs */
                                 FD_SET (server.csock, &readfs); /* adds a stream */
            
                                 timeout.tv_sec = 15; /* 15 s */
            
                                 err =
                                    select (server.csock + 1, &readfs, NULL, NULL,
                                            &timeout);
            
                                 switch (err)
                                 {
                                 case 0:
                                    puts ("timeout");
                                    err = 1;
                                    break;
                                 case -1:
                                    puts ("error");
                                    err = 1;
                                    break;
                                 default:
                                    if (FD_ISSET (server.csock, &readfs))
                                    {
                                       char buffer[128];
                                       err = recoit (server.csock, buffer, sizeof buffer);
                                       if (!err)
                                       {
                                          err =
                                             envoi (server.csock, buffer,
                                                    strlen (buffer));
                                       }
                                    }
                                    else
                                    {
                                       puts ("event on an unknown socket\n");
                                    }
                                 }
                              }
                              while (!err);
                           }
                           /* Il ne faut pas oublier de fermer la connexion (fermée dans les deux sens) */
                           shutdown (server.csock, 2);
                        }
                     }
            
                     /* Fermeture de la socket */
                     printf ("Fermeture de la socket...\n");
                     closesocket (server.sock);
                     printf ("Fermeture du serveur terminee\n");
                  }
                  WSACleanup ();
               }
            
               return EXIT_SUCCESS;
            }
            
            • Partager sur Facebook
            • Partager sur Twitter
            Music only !

            [socket] faire un timeout

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown