IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

problème de socket bloquante


Sujet :

C

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    47
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 47
    Points : 41
    Points
    41
    Par défaut problème de socket bloquante
    Bonjour,

    je désire porter une application WinXP vers Linux Ubuntu.

    Pour les besoins du projet, j’utilise des sockets pour échanger diverses données entre plusieus processus.
    Je souhaite configurer mes sockets comme non bloquantes.

    Mon processus principal (core) créé une socket d’écoute « listen_socket[SockID] ](cf ci dessous).

    Les autres process viennent se connecter au process principal via une socket de service.

    Voici mon problème :
    Sous WinXP, j’arrive bien à configurer mes sockets comme non bloquantes, mais sous Linux, ça ne fonctionne pas comme prévu.

    Mon processus principal reste bloqué lors d’un read sur la socket de service jusqu’à ce qu’il reçoive un message de l’un des processus clients.
    C’est très embêtant car le processus core doit être apte à poursuivre son job malgré qu’aucune donnée ne lui ai été envoyée par un des clients.




    Je poste ci dessous un extrait de chacune des fonctions qui crée:
    - La socket d’écoute pour le processus principal.

    L'option SockID me permet ensuite de pouvoir ré accéder à plusieurs sockets créées (stockage du descripteur retourné dans l'un ou l'autre des 2 tableaux définis comme globaux et dont la déclaration ne figure pas ici.)


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    int Create_ListenSocket(u_short nPort, int SockID) 
    {
    	if (SockID > ListenAllocated-1)
    	{
    		fprintf(stderr, "\nUnable to create listening socket! Please Allocate first with Alloc_ClientSocks(int nb);\n");
    		return (0);
    	}
     
    	struct sockaddr_in my_addr;
    	int state_flags = 0;
     
    	listen_socket[SockID] = socket(AF_INET, SOCK_STREAM, 0);
     
    	if (listen_socket[SockID] == -1)
    	{
    		fprintf(stderr, "\nError while creating Listen socket[%d], error code: %d\n", SockID, errno); 
    		printf("Error: %d\n", errno);
    		return (0);
    	}
    	else
    	  printf("Listen-socket() sockfd is OK...\n");
     
     
    	/* host byte order */
    	my_addr.sin_family = AF_INET;
     
    	/* short, network byte order */
    	my_addr.sin_port = htons(nPort);
    	my_addr.sin_addr.s_addr = INADDR_ANY;
     
    	/* zero the rest of the struct */
    	memset(&(my_addr.sin_zero), 0, 8);
     
     
     
    	if(bind(listen_socket[SockID], (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
    	{
    		perror("bind() error on listen socket!\n");
    		printf("Error: %d\n", errno);	
    		return (0);
    	}
    	else
    	  printf("bind() is OK...\n");
     
     
    	// setup listen_socket[SockID] as NON BLOCKING
    	state_flags = fcntl (listen_socket[SockID], F_GETFL);
    	if (fcntl(listen_socket[SockID], F_SETFL, state_flags | O_NONBLOCK) < 0)
    		printf("\nUnable to put listening Socket in unblocking mode\n");
     
    	return (1);
    }


    - La socket de service pour les autres processes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    int Create_ServiceSocket(const char* ipadd, u_short nPort, int SockID) 
    { 
    	if (SockID > ClientAllocated-1)
    	{
    		fprintf(stderr, "\nUnable to create client socket! first allocate with Alloc_ListenSocks(int nb);");
    		return 0;
    	}	
     
    	struct sockaddr_in sin;          /* déclaration de la structure sockaddr_in */ 
    	int state_flags = 0;			/* pour sauvegarder les flags de configuration de cette socket */
     
    	memset(&sin, 0x0, sizeof(struct sockaddr_in)); 
    	sin.sin_addr.s_addr		= inet_addr(ipadd);			/* définit l'adresse IP du server */
    	sin.sin_family				= AF_INET;							/* famille du socket */ 
    	sin.sin_port					= htons(nPort);					/* port */ 
     
    	service_socket[SockID] = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); /* appel de la fonction socket */ 
     
    	if(service_socket[SockID] != -1)
    	{
    		if (DEBUG_SOCKET_API)
    			fprintf(stdout, "\n[*] Service(client) Socket[%d] successfuly created.\n", SockID); 
    	}
    	else
    	{ 
    		fprintf(stderr, "\nError while creating Service socket[%d], error code: %d\n", SockID, errno); 
    		return(0); 
    	}
     
     
    	if (DEBUG_SOCKET_API)
    		fprintf(stdout, "\nConnection to server\n");
     
    	if (!connect(service_socket[SockID], (sockaddr *)&sin, sizeof(struct sockaddr_in)) )
    	{
    		if (DEBUG_SOCKET_API)
    			fprintf(stdout, " OK!");
    	}
    	else
    		return(0);	// unable to connect to server!
     
     
     
     
    	// setup service_socket[SockID] as NON BLOCKING
    	state_flags = fcntl (service_socket[SockID], F_GETFL);
    	if (fcntl(service_socket[SockID], F_SETFL, state_flags | O_NONBLOCK) < 0)
    		printf("\nUnable to put 'client' Socket in unblocking mode\n");
     
    	return(1);
    }









    J’utilise ce code pour configurer en mode non bloquant (j'avais trouvé la fonction fcntl(...) sous Linux équivalente à FIONBIO(...) je crois sous Win....:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // setup listen_socket[SockID] as NON BLOCKING
    	state_flags = fcntl (listen_socket[SockID], F_GETFL);
    	if (fcntl(listen_socket[SockID], F_SETFL, state_flags | O_NONBLOCK) < 0)      // ajout du flag O_NONBLOCK
    		printf("\nUnable to put listening Socket in unblocking mode\n");

    C'est terrible, ça fait un moment que je bloque là dessus, peut-être sauriez vous m'éclairer sur un oubli ou une erreur dans ces fonctions de création et d'initialisation?

    Merci par avance

  2. #2
    Membre éclairé Avatar de |PaRa-BoL
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 738
    Points : 876
    Points
    876
    Par défaut
    Hm, à priori je ne vois pas de problème.
    Par contre il faut le set en non bloquant avant le "connect()" et vérifier grâce à un évènement "write" sur le socket que la connexion est établie :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    [boucle event (select()/poll()/epoll(), etc...]
    	[event write && si dernier état du socket == EINPROGRESS]
    		ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &serror, &serror_len);
    		if (ret == 0 && serror == 0) {
    				// fd est connecté
    		}
    	[/event]
    [/boucle]
    Ton socket "bindé" et tes sockets "clients" on tous le même problème?

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    47
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 47
    Points : 41
    Points
    41
    Par défaut
    Je vais remonter le bloc de code juste au dessus du Connect() pour essayer.

    Pour répondre à ta question, seule la socket "bindée" (côté serveur) est bloquante, le client (il y en a qu'un pour l'instant) lui fonctionne à la perfection et m'envoie bien un message du style "RAS" s'il n'a pas reçu de données.

    Je poste là suite dès que j'aurai fait les tests.
    Je te remercie pour ta réponse.

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    47
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 47
    Points : 41
    Points
    41
    Par défaut
    Ouah ça marche , mais en mode bloquant!

    J'ai ajouté l'instruction select() dans ma fonction read:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    int read_datas(char* buffer, int SockID) 
    { 
      int ret = 0;
      timeout.tv_sec = 0;
      timeout.tv_usec = 500000;
     
      FD_ZERO(&socks); 
      FD_SET(service_socket[SockID], &socks); 
     
     
      readsocks = select(service_socket[SockID]+1, &socks, (fd_set *) 0, (fd_set *) 0, &timeout);
     
      if (readsocks < 0)
      {
         printf("\nSelect() Error!\n");
         exit(EXIT_FAILURE);
      }
     
      if (readsocks == 0)	/* Nothing to read, just show that we're alive */
      {
         //printf("Nothing to read...\n");
      }
      else ret = recv(service_socket[SockID], buffer, MESSAGE_SIZE, 0);
     
      if (ret)
        return 0;
      else
        return -1;
    }


    Concernant le problème qui a conduit à l'ouverture de ce post et pour faire avancer la discussion, voici les manipulation effectuées:

    1) Code ci dessous placé juste avant le connect()

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // setup service_socket[SockID] as NON BLOCKING
    	state_flags = fcntl (service_socket[SockID], F_GETFL);
    	if (fcntl(service_socket[SockID], F_SETFL, state_flags | O_NONBLOCK) < 0)
    		printf("\nUnable to put 'client' Socket in unblocking mode\n");
    => Le connect() renvoie alors systématiquement l'erreur 115 (EINPROGRESS) (apparement normal)

    2) Ajout de la close select(), si erreur 115.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    if (!connect(service_socket[SockID], (sockaddr *)&sin, sizeof(struct sockaddr_in)) )
    {
      if (DEBUG_SOCKET_API)
        fprintf(stdout, "\nconnect(): OK!");
    }
    else
    {
      fprintf(stdout, "\nconnect(): ERROR n. %d", errno);	
      if (errno == EINPROGRESS)		// error 115
      {			
        fd_set rfds;
        struct timeval tv;
        int retval;
     
        tv.tv_sec = 50; tv.tv_usec = 0;
        printf("\nperforming select(...)\n");
     
        retval = select(service_socket[SockID]+1, &rfds, NULL, NULL, &tv); 
        if (retval)
          printf("\n now ok!\n"); /* FD_ISSET(0, &rfds) will be true. */
        else
          printf("\n no change within 50 seconds.\n");
      }

    --> A partir de là c'est devenu flou dans ma tête:

    [event write && si dernier état du socket == EINPROGRESS]
    ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &serror, &serror_len);
    if (ret == 0 && serror == 0)
    {
    // fd est connecté
    }
    [/event]
    => Je ne vois pas où/quand faire le write sur cette socket et comment gérer l'ensemble constitué par select()

Discussions similaires

  1. Problème Swing / socket bloquant
    Par soussou92 dans le forum AWT/Swing
    Réponses: 0
    Dernier message: 12/05/2010, 13h29
  2. Problème de socket bloquant et select sans effet.
    Par asmerisme dans le forum Réseau
    Réponses: 5
    Dernier message: 23/02/2010, 18h55
  3. Réponses: 2
    Dernier message: 26/03/2004, 09h15
  4. [Kylix] Problème de socket
    Par RaygKross dans le forum EDI
    Réponses: 1
    Dernier message: 01/03/2004, 19h41
  5. Mysql ne se lance pas problème de socket
    Par Riko dans le forum Installation
    Réponses: 5
    Dernier message: 05/02/2004, 09h28

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo