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

Réseau C Discussion :

Problème de socket marche pas?


Sujet :

Réseau C

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    134
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mars 2006
    Messages : 134
    Par défaut Problème de socket marche pas?
    Bonjour, voici mon probleme j'essaye de faire sur 2 sockets, alors sur un socket je recoit un ordre typiquement une chaine de caractere que je convertier en entier. Si cette odre est different de 0 alors on s'arrete d'envoyer sinon on continue.
    Mon ordre que j'envoie, je l'ai verifier il fonctionne c'est "11".
    Avec ce code la valeur que me renvoie recv est -1 et je ne sais pas pourquoi
    Pouvez vous m'aider a chercher d'ou viens mon erreur merci.

    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
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
     
    /********************************************************************/
    /*                                                                  */
    /*	 essai client    TCP                                            */
    /*                                                                  */
    /********************************************************************/
     
     
    #include <stdio.h>
    #include <winsock2.h>
    #include <string.h>
    #pragma comment(lib, "ws2_32.lib")
     
    void main()
    {
    	int i=0;
    	int ordre=0;
    	int n=0;
    	int fin=0;
     
    	char buffer[255];
     
    	WSADATA WSAData;
    	WSAStartup(MAKEWORD(2,0), &WSAData);
     
     
    	//Socket 1 celui de la reception des ordre**************************************
    	SOCKET sock;
    	SOCKADDR_IN sin;
     
    	//CREATION d'un socket
    	/* Tout est configuré pour se connecter sur ma propre machine */
    	sock = socket(AF_INET, SOCK_STREAM, 0); // Mode TCP configurer ici
    	printf("Socket 1 %d\n",sock);
    	sin.sin_addr.s_addr			= inet_addr("172.24.247.84"); //adress
    	sin.sin_family				= AF_INET; //domaine
    	sin.sin_port				= htons(5000); // port
     
    	//un bind toujours avant un listen
    	if(	bind(sock, (SOCKADDR *)&sin, sizeof(sin)) <0)
    		printf("ERREUR dans le bind\n");
    	else
    		printf("Bind 1 OK\n");
     
    	 //On ecoute le socket sock
    	if(	listen(sock, 0) <0 )
    		printf("ERREUR dans le listen 1\n");
    	else
    		printf("Listen 1 OK\n");
     
    	//ACCEPTATION
    	int val;
    	int lgsockaddr= sizeof(sin);
    	printf("ACCEPT 1 ");
    	val = accept(sock, (SOCKADDR *)&sin, &lgsockaddr );
    	if(val != INVALID_SOCKET)
    	{
    		printf("%d\n",val);
    	}
     
     
    	//Socket 2 celui de l'envoie des données*************************************
    	SOCKET sock2;
    	SOCKADDR_IN sin2;
     
    	//CREATION d'un socket
    	// Tout est configuré pour se connecter sur ma propre machine 
    	sock2 = socket(AF_INET, SOCK_STREAM, 0); // Mode TCP configurer ici
    	printf("Socket 2 %d\n",sock2);
    	sin2.sin_addr.s_addr			= inet_addr("172.24.247.84"); //adress
    	sin2.sin_family				= AF_INET; //domaine
    	sin2.sin_port				= htons(5001); // port
     
    	//un bind toujours avant un listen
    	if(	bind(sock2, (SOCKADDR *)&sin2, sizeof(sin2)) <0)
    		printf("ERREUR dans le bind 2\n");
    	else
    		printf("Bind 2 OK\n");	
     
    	 // On ecoute le socket sock
    	if(	listen(sock2, 0) <0 )
    		printf("ERREUR dans le listen 2\n");
    	else
    		printf("Listen 2 OK\n");
     
    	//ACCEPTATION
    	int val2;
    	int lgsockaddr2= sizeof(sin2);
    	printf("ACCEPT 2 ");
    	val2 = accept(sock2, (SOCKADDR *)&sin2, &lgsockaddr2 );
    	if(val2 != INVALID_SOCKET)
    	{
    		printf("%d\n",val2);
    	}
     
     
    	//Ouverture de fichier*****************************************************
    	FILE* fichier;
    	fichier=fopen("donnees.dat","r");
     
    	if(fichier==NULL)
    	{
    		printf("Erreur a l'ouverture du fichier\n");
    		exit(1);
    	}
     
    	while(fin!=EOF)
    	{
    		fin=fscanf(fichier,"%c",&buffer[n]);
    		n++;
    	}
    	fclose (fichier);
     
    	//VERIFICATION de la lecture du fichier	
    	/*
    	while(i!=n)
    	{
    		printf ("%c\n",buffer[i]);
    		i++;
    	}
    	*/
     
    	char reception[1];
    	while(ordre==0)
    	{
    		//Reception Ordre
    		int aux;
    		printf("Pause\n");
    		scanf("%d",&i);
    		aux=recv(val, reception, sizeof(&reception), 0);
    		printf("%d\t",aux);
    		ordre=atoi(reception);
    		printf("%d\n",ordre);
     
    		/*
    		n=0;
    		while(n==10)
    		{
    			n++;
    			send(val2,buffer,sizeof(buffer), 0); 		
    		}
    		*/
    		//printf("Pause\n");
    		//scanf("%d",&i);
    	}
     
     
     
    	//Fermeture de la connection
    	if( closesocket(sock) <0 )
    	{
    		printf("ERREUR de fermeture de connection\n");
    	}
    	else
    	{
    		printf("Fermeture connection OK\n");
    	}
    	WSACleanup();
    }
    bien pratique ces balise de code.

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Tu fais ton recv() sur le socket d'écoute (sock, sock2) au lieu de le faire sur le socket accepté (val, val2)...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    134
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mars 2006
    Messages : 134
    Par défaut
    tu vient de mapprendre un truc val et val2 sont des socket accepter wahou merci

    autre chose aussi saurait tu comment avec la fonction FCNTL je peut rendre mets socket non bloquant ou bloquant enfin que je puisse choisir leur mode de fonctionnement. J'ai regarder la man page sur FCNTL et sa n maide pas plus que sa.
    Dans tous les cas merci

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    134
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mars 2006
    Messages : 134
    Par défaut
    J'essaye de faire exactement la meme chose mais avec un socket udp ma reception ne marche pas jai -1 a quoi cela est du? Merci

    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
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
     
    /********************************************************************/
    /*                                                                  */
    /*	 essai client    TCP                                            */
    /*                                                                  */
    /********************************************************************/
     
     
    #include <stdio.h>
    #include <winsock2.h>
    #include <string.h>
    #include <fcntl.h>
     
    #pragma comment(lib, "ws2_32.lib")
     
    void main()
    {
    	int i=0;
    	int ordre=0;
    	int n=0;
    	int fin=0;
     
    	char buffer[20];
     
    	WSADATA WSAData;
    	WSAStartup(MAKEWORD(2,0), &WSAData);
     
     
    	//Socket 1 celui de la reception des ordre**************************************
    	SOCKET sock;
    	SOCKADDR_IN sin;
     
    	//CREATION d'un socket
    	/* Tout est configuré pour se connecter sur ma propre machine */
    	sock = socket(AF_INET, SOCK_DGRAM, 0); // Mode TCP configurer ici
    	//u_long valu = 0; 
    	//ioctlsocket(sock, FIONBIO,&valu);
     
    	printf("Socket 1 %d\n",sock);
    	sin.sin_addr.s_addr			= htonl(INADDR_ANY); //adress
    	sin.sin_family				= AF_INET; //domaine
    	sin.sin_port				= htons(5000); // port
     
    	//un bind toujours avant un listen
    	if(	bind(sock, (SOCKADDR *)&sin, sizeof(sin)) <0)
    		printf("ERREUR dans le bind\n");
    	else
    		printf("Bind 1 OK\n");
     
     
    	//Socket 2 celui de l'envoie des données*************************************
    	SOCKET sock2;
    	SOCKADDR_IN sin2;
     
    	//CREATION d'un socket
    	// Tout est configuré pour se connecter sur ma propre machine 
    	sock2 = socket(AF_INET, SOCK_DGRAM, 0); // Mode TCP configurer ici
    	printf("Socket 2 %d\n",sock2);
    	sin2.sin_addr.s_addr			= inet_addr("172.24.247.84"); //adress
    	sin2.sin_family				= AF_INET; //domaine
    	sin2.sin_port				= htons(5001); // port
     
    	//un bind toujours avant un listen
    	if(	bind(sock2, (SOCKADDR *)&sin2, sizeof(sin2)) <0)
    		printf("ERREUR dans le bind 2\n");
    	else
    		printf("Bind 2 OK\n");	
     
     
    	//Ouverture de fichier*****************************************************
    	FILE* fichier;
    	fichier=fopen("donnees.dat","r");
     
    	if(fichier==NULL)
    	{
    		printf("Erreur a l'ouverture du fichier\n");
    		exit(1);
    	}
     
    	while(fin!=EOF)
    	{
    		fin=fscanf(fichier,"%c",&buffer[n]);
    		n++;
    	}
    	fclose (fichier);
     
    	//VERIFICATION de la lecture du fichier	
    	/*
    	while(i!=n)
    	{
    		printf ("%c\n",buffer[i]);
    		i++;
    	}
    	*/
     
    	char reception[1];
    	while(ordre==0)
    	{
    		//Reception Ordre
    		int aux,aux2;
    		int lg_addr=sizeof(sin);
    		aux=recvfrom(sock, reception, sizeof(&reception), 0, (struct sockaddr *)&sin, &lg_addr);
    		//printf("arret\n");
    		printf("Reception %d\n",aux);
    		ordre=atoi(reception);
    		printf("Ordre recu %d\n",ordre);
     
     
    		n=0;
    		while(n<10)
    		{
    			n++;
    			aux2=sendto(sock2, buffer, sizeof(&buffer) , 0, (struct sockaddr *) &sin2, sizeof(sin2));	
    			printf("Envoie %d\t",aux2);
    		}
    	}
     
    		printf("Pause\n");
    		scanf("%d",&i);
     
    	//Fermeture de la connection
    	if( ((closesocket(sock)<0)|(closesocket(sock2)<0)) )
    	{
    		printf("ERREUR de fermeture de connection\n");
    	}
    	else
    	{
    		printf("Fermeture connection OK\n");
    	}
    	WSACleanup();
    }

  5. #5
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par doommick31
    autre chose aussi saurait tu comment avec la fonction FCNTL je peut rendre mets socket non bloquant ou bloquant enfin que je puisse choisir leur mode de fonctionnement. J'ai regarder la man page sur FCNTL et sa n maide pas plus que sa.
    Dans tous les cas merci
    A ma connaissance, il n'y a pas de fcntl() sous Windows et d'autre part, ça sert à quoi un socket non bloquant ? Utilise plutôt les threads...

    http://emmanuel-delahaye.developpez.com/reseaux.htm
    http://emmanuel-delahaye.developpez.com/pthreads.htm

  6. #6
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par doommick31
    J'essaye de faire exactement la meme chose mais avec un socket udp ma reception ne marche pas jai -1 a quoi cela est du? Merci

    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
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
     
    /********************************************************************/
    /*                                                                  */
    /*	 essai client    TCP                                            */
    /*                                                                  */
    /********************************************************************/
     
     
    #include <stdio.h>
    #include <winsock2.h>
    #include <string.h>
    #include <fcntl.h>
     
    #pragma comment(lib, "ws2_32.lib")
     
    void main()
    {
    	int i=0;
    	int ordre=0;
    	int n=0;
    	int fin=0;
     
    	char buffer[20];
     
    	WSADATA WSAData;
    	WSAStartup(MAKEWORD(2,0), &WSAData);
     
     
    	//Socket 1 celui de la reception des ordre**************************************
    	SOCKET sock;
    	SOCKADDR_IN sin;
     
    	//CREATION d'un socket
    	/* Tout est configuré pour se connecter sur ma propre machine */
    	sock = socket(AF_INET, SOCK_DGRAM, 0); // Mode TCP configurer ici
    	//u_long valu = 0; 
    	//ioctlsocket(sock, FIONBIO,&valu);
     
    	printf("Socket 1 %d\n",sock);
    	sin.sin_addr.s_addr			= htonl(INADDR_ANY); //adress
    	sin.sin_family				= AF_INET; //domaine
    	sin.sin_port				= htons(5000); // port
     
    	//un bind toujours avant un listen
    	if(	bind(sock, (SOCKADDR *)&sin, sizeof(sin)) <0)
    		printf("ERREUR dans le bind\n");
    	else
    		printf("Bind 1 OK\n");
     
     
    	//Socket 2 celui de l'envoie des données*************************************
    	SOCKET sock2;
    	SOCKADDR_IN sin2;
     
    	//CREATION d'un socket
    	// Tout est configuré pour se connecter sur ma propre machine 
    	sock2 = socket(AF_INET, SOCK_DGRAM, 0); // Mode TCP configurer ici
    	printf("Socket 2 %d\n",sock2);
    	sin2.sin_addr.s_addr			= inet_addr("172.24.247.84"); //adress
    	sin2.sin_family				= AF_INET; //domaine
    	sin2.sin_port				= htons(5001); // port
     
    	//un bind toujours avant un listen
    	if(	bind(sock2, (SOCKADDR *)&sin2, sizeof(sin2)) <0)
    		printf("ERREUR dans le bind 2\n");
    	else
    		printf("Bind 2 OK\n");	
     
     
    }
    Tu mets un serveur et un client dans la même application ? C'est bizarre, et je serais étonné que ça fonctionn(e|ât ?)...

    (en plus, tes commentaires sont bizarres...)

  7. #7
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    ... d'autre part, ça sert à quoi un socket non bloquant ?
    ..
    A faire un vrai serveur au sens service sous *n*x

    Qui ne fait RIEN (sleep) jusqu'à ce qu'une demande lui arrive...

    Comme je disais au début de mon arrivée sur ce site, c'est (c'était ?) la manière standard des *n*xiens pour faire des serveurs, et c'est comme ça que fonctionnent (fonctionnaient ?) mail, ftp, telnet, et tous les services répertoriés dans /etc/services.

    Et comme je l'avais dit dans cette discussion, en tous cas avec mon expérience jusqu'il y à 5 ou 6 ans, la notion de thread n'était ni connue ni utlisée vraiment sous *n*x. J'ai moi-même fait des réseaux de serveurs/services sans thread, sans même savoir ce que c'était....

  8. #8
    Membre Expert
    Avatar de InOCamlWeTrust
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 036
    Par défaut
    Oui, les thread POSIX sont mal-aimés de la communauté Unix, et dans un certains sens c'est vrai que leur utilisation aujourd'hui assez abusive et très automatique ne se justifie pas toujours, entre autres lorsque les thread n'ont pas à accéder à des données communes, partagées, autant faire des fork().

    J'ai lu une remarque qui me semblait assez intéressante de la part de celui qui a écrit le livre "L'art de la programmation sous Unix" : il y disait que certes le changement de contexte entre thread POSIX est moins coûteux, mais que les opérations classiques de gestion d'exclusion mutuelle et de réveil sur condition, par exemple, coûteuses selon lui, les rendaient en pratique beaucoup moins avantageux que les thread Unix classiques à la fork()...

  9. #9
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    D'ailleurs, je me demande (en fait j'en suis presque certain) si la notion de thread et ses applications pour les serveurs ne vient pas de Windows et de sa non-conforimté au modèle en couches ISO, et donc de moyens détournés pour pallier à un défaut intrinsèque.

    En effet, c'était une des raisons pour lesquelles je n'avais pas porté mon code sous Windows : la routine (je ne me souviens plus son nom) qui sous Windows permettait le déblocage d'un socket en mode non bloquant prenait comme paramètre un ID de fenêtre pour renvoyer le résultat, en violation de toutes les règles des couches, alors que sous tous les autres systèmes, la couche transport/interruptions était bien séparée et indépendante des autres (et d'ailleurs M$ était très fier de cette "feature" qu'il mettait en avant comme "avantage" dans sa doc système, pour envoyer les messages vers un client).

    Alors que sous par exemple tous les systèmes *n*x, come la routine rendant en mode non-bloquant était similaire à celle rendant en mode bloquant, et fonctionnait avec une routine du style de celles passés quand on veut réceptionner un signal, la tâche communication était juste au dessus de la couche transport, totalement séparée des applis.. (voir les sources des serveurs dispo. y compris ici-même).

    [exemple : ce qui pour moi permettait d'avoir une bibliothèque de manipulation de sockets accessibles aussi bien par des serveurs que des applis à GUI complexe. Et sous Windows un "serveur" devait (doit ?) toujours fonctionner en mode "console" car il fallait (faut ?) un id de fenêtre]

  10. #10
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Attention: Pour faire de l'événementiel sur les sockets, il n'est pas nécessaire qu'ils soient non-bloquants: select() marche parfaitement avec des sockets bloquants.

    Les "sockets non-bloquants" de Linux, basés sur SIGPOLL, suivent une autre philosophie que la programmation événementielle: La programmation interruptible, qui est une autre paire de manches à programmer.

    Sous Windows, il y a la conformité au niveau sockets bloquants (select() marche sur les sockets, même si elle ne marche QUE sur eux), mais les sockets non-bloquants sont en programmation événementielle seulement:
    • Soit avec une fonction d'attente similaire à select() mais plus évoluée (WSAEventSelect() + WSAWaitForMultipleEvents()),
    • soit avec une fonction agissant directement sur le système de files de messages de Windows (WSAAsyncSelect(), qui poste des messages vers une fenêtre, la fonction dont se plaignait souviron34). Cela vient du fait que sous Windows, les fenêtres sont les destinataires traditionnels des messages Windows, plutôt que les threads qui hébergent la file de message.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  11. #11
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    c'est bien ce que je disais


    Sauf que si tu utilises un socket bloquant avec select, ton serveur (ou client) ATTEND, et donc utilise du CPU, et tourne dans la liste des process. (et en plus l'attente se fait avec un time-out, que tu ne peux pas préciser > à une certaine valeur).

    C'est bien pour ça que sous *n*x on utilisait des sockets non-bloquants.. où tu peux avoir un serveur branché 24/24, 7/7, 365/365, qui reçoit un évènement tous les 3 mois....., et qui, le reste du temps, consomme 0 CPU.

    Et de plus, contrairement à *n*x, où les sockets sont des files descriptors comme quasi n'importe quel file descriptor, ce que tu appelles "la file de messages" n'en est pas une sous *n*x, puisque c'est "l'écriture dans un fichier" (spécial, on est d'accord), et donc cette fameuse routine (la seule équivalente qui est effectivement WSAAsyncSelect) nécessite effectivement un window handle, qui viole totalement les couches. C'est exactement ce principe des files de messages dont M$ était si fier dans sa doc système. Et qui, à mon avis, a entraîné (entre autre) l'utilisation des threads.

    Le terme même de thread m'était inconnu sous *n*x, à plus forte raison le multi-thread.

    Il y a déjà assez à faire avec les sockets


    Je donne un exemple : une des applications que j'ai eu à faire était un réseau de serveurs recevant des données, certains toutes les 3 heures, d'autres toutes les 5 minutes, d'autres 2500 par seconde pendant 2 mois puis rien pendant 3 mois, etc.. D'où l'intérêt d'un socket non-bloquant ..

    Et d'ailleurs le code n'était pas parti de ma tête : c'est le code original du CERN/NCSA pour la première version de Mosaic (1994. HTTP 1.0).

  12. #12
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par souviron34
    Sauf que si tu utilises un socket bloquant avec select, ton serveur (ou client) ATTEND, et donc utilise du CPU, et tourne dans la liste des process.
    D'où ma question, "un socket non bloquant, pourquoi faire ?"

  13. #13
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Citation Envoyé par souviron34
    Sauf que si tu utilises un socket bloquant avec select, ton serveur (ou client) ATTEND, et donc utilise du CPU, et tourne dans la liste des process.
    Perdu.
    select() est un appel système, donc sous tout kernel évolué, l'attente est passive.
    (et en plus l'attente se fait avec un time-out, que tu ne peux pas préciser > à une certaine valeur).
    Mais on peut dire "pas de timeout", ce qui signifie "attendre indéfiniment". Hé oui, "pas de timeout" est différent de "timeout nul".
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  14. #14
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Pour terminer là-dessus ( ) juste 3 remarques :
    • 1) tous les code-sources de serveurs pour Windows disponibles sur le Web en 2001 (ce qui n'est pas anté-diluvien ) se comportaient avec une boucle de lecture sur le port 80 toutes les secondes pour vérifier si il y avait quelque chose à lire (pour éviter le fameux ID de fenêtre de la routine Windows ??)

    • 2) Comme l'a justement dit Médinoc, c'est la différence entre événementiel et interruptible. Si l'on prend un exemple qui te parleras peut-être plus, Emmanuel, c'est la différence entre PUSH et PULL :

      • tous les sites que je vois (y compris d'ailleurs sur ce forum) fonctionnent avec la philosophie PUSH : soit l'utilisateur doît rafraîchir de lui-même la page, soit le programme va vérifier toutes les N secondes/minutes si quelque chose de nouveau est arrivé.
      • Mais on peut voir un intérêt à une philosophie PULL : qu'un GUI (ou une page) soit AUTOMATIQUEMENT averti(e) qu'un nouvel événement est arrivé. Ce qui était mon cas (et à mon avis devrait être le cas de beaucoup d'applications) : je fais un GUI qui surveille des événements en temps réel. Mais ce GUI dispose de plein d'autres fonctionalités qui peuvent être activées par l'utilisateur PENDANT le mode temps réel, et qui donc se passent concommitamment avec l'arrivée (ou non) d'événements.


    • 3) voici l'intégrale de la page du man linux sur les sockets (obtenue par "man 7 socket") sur mon RedHat 7.3, qui correspond à la définition de 1995 de Linux. Si vous y voyez une quelconque référence aux threads, prévenez-moi... :


    man 7 socket


    SOCKET(7) Linux Programmer's Manual SOCKET(7)

    NAME
    socket - Linux socket interface

    SYNOPSIS
    #include <sys/socket.h>
    mysocket = socket(int socket_family, int socket_type, int protocol);

    DESCRIPTION
    This manual page describes the Linux networking socket layer user
    interface. The BSD compatible sockets are the uniform interface
    between the user process and the network protocol stacks in the
    kernel. The protocol modules are grouped into protocol families like
    PF_INET, PF_IPX, PF_PACKET and socket types like SOCK_STREAM
    or SOCK_DGRAM. See socket(2) for more information on families and
    types.

    SOCKET LAYER FUNCTIONS
    These functions are used by the user process to send or receive
    packets and to do other socket operations. For more information
    see their respective manual pages.

    socket(2) creates a socket, connect(2) connects a socket to a
    remote socket address, the bind(2) function binds a socket to a
    local socket address, listen(2) tells the socket that new connections
    shall be accepted, and accept(2) is used to get a new socket with a
    new incoming connection. socketpair(2) returns two connected
    anonymous sockets (only implemented for a few local families like
    PF_UNIX)

    send(2), sendto(2), and sendmsg(2) send data over a socket, and
    recv(2), recvfrom(2), recvmsg(2) receive data from a socket. poll(2)
    and select(2) wait for arriving data or a readiness to send data. In
    addition, the standard I/O operations like write(2), writev(2), sendfile
    (2), read(2), and readv(2) can be used to read and write data.

    getsockname(2) returns the local socket address and getpeername(2)
    returns the remote socket address. getsockopt(2) and setsockopt(2)
    are used to set or get socket layer or protocol options. ioctl(2)
    can be used to set or read some other options.

    close(2) is used to close a socket. shutdown(2) closes parts of a full
    duplex socket connection.

    Seeking, or calling pread(2) or pwrite(2) with a non-zero position is
    not supported on sockets.

    It is possible to do non-blocking IO on sockets by setting the
    O_NONBLOCK flag on a socket file descriptor using fcntl(2).
    Then all operations that would block will (usually) return with EAGAIN
    (operation should be retried later); connect(2) will return
    EINPROGRESS error. The user can then wait for various events via
    poll(2) or select(2).

    +--------------------------------------------------------------------+
    | I/O events |
    +-----------+-----------+--------------------------------------------+
    |Event | Poll flag | Occurrence |
    +-----------+-----------+--------------------------------------------+
    |Read | POLLIN | New data arrived. |
    +-----------+-----------+--------------------------------------------+
    |Read | POLLIN | A connection setup has been completed (for |
    | | | connection-oriented sockets) |
    +-----------+-----------+--------------------------------------------+
    |Read | POLLHUP | A disconnection request has been initiated |
    | | | by the other end. |
    +-----------+-----------+--------------------------------------------+
    |Read | POLLHUP | A connection is broken (only for connec- |
    | | | tion-oriented protocols). When the socket |
    | | | is written SIGPIPE is also sent. |
    +-----------+-----------+--------------------------------------------+
    |Write | POLLOUT | Socket has enough send buffer space for |
    | | | writing new data. |
    +-----------+-----------+--------------------------------------------+
    |Read/Write | POLLIN| | An outgoing connect(2) finished. |
    | | POLLOUT | |
    +-----------+-----------+--------------------------------------------+
    |Read/Write | POLLERR | An asynchronous error occurred. |
    +-----------+-----------+--------------------------------------------+
    |Read/Write | POLLHUP | The other end has shut down one direction. |
    +-----------+-----------+--------------------------------------------+
    |Exception | POLLPRI | Urgent data arrived. SIGURG is sent then. |
    +-----------+-----------+--------------------------------------------+

    An alternative to poll/select is to let the kernel inform the application
    about events via a SIGIO signal. For that the FASYNC flag must be set
    on a socket file descriptor via fcntl(2) and a valid signal handler for
    SIGIO must be installed via sigaction(2). See the SIGNALS discussion
    below.

    SOCKET OPTIONS
    These socket options can be set by using setsockopt(2) and read
    with getsockopt(2) with the socket level set to SOL_SOCKET for all
    sockets:

    SO_KEEPALIVE
    Enable sending of keep-alive messages on connection-oriented
    sockets.
    Expects a integer boolean flag.

    SO_OOBINLINE
    If this option is enabled, out-of-band data is directly placed into
    the receive data stream. Otherwise out-of-band data is only
    passed when the MSG_OOB flag is set during receiving.

    SO_RCVLOWAT and SO_SNDLOWAT
    Specify the minimum number of bytes in the buffer until the
    socket layer will pass the data to the protocol (SO_SNDLOWAT) or
    the user on receiving (SO_RCVLOWAT). These two values are
    not changeable in Linux and their argument size is always fixed to
    1 byte. getsockopt is able to read them; setsockopt will
    always return ENOPROTOOPT.

    SO_RCVTIMEO and SO_SNDTIMEO
    Specify the sending or receiving timeouts until reporting an error.
    They are fixed to a protocol specific setting in Linux and cannot
    be read or written. Their functionality can be emulated
    using alarm(2) or

    SO_BSDCOMPAT
    Enable BSD bug-to-bug compatibility. This is used only by the
    UDP protocol module and scheduled to be removed in future.
    If enabled ICMP errors received for a UDP socket will not be passed
    to the user program. Linux 2.0 also enabled BSD bug-to-bug
    compatibility options (random header changing, skipping of the
    broadcast flag) for raw sockets with this option, but that
    has been removed in Linux 2.2. It is better to fix the user programs
    than to enable this flag.

    SO_PASSCRED
    Enable or disable the receiving of the SCM_CREDENTIALS control
    message.
    For more information see unix(7).

    SO_PEERCRED
    Return the credentials of the foreign process connected to this
    socket.
    Only useful for PF_UNIX sockets; see unix(7). Argument is a ucred
    structure. Only valid as a getsockopt.

    SO_BINDTODEVICE
    Bind this socket to a particular device like "eth0", as specified in
    the passed interface name. If the name is an empty string or
    the option length is zero, the socket device binding is removed.
    The passed option is a variable-length null terminated interface
    name string with the maximum size of IFNAMSIZ. If a socket is
    bound to an interface, only packets received from that particular
    interface are processed by the socket. Note that this only works
    for some socket types, particularly AF_INET sockets.
    It is not supported for packet sockets (use normal bind(8) there).

    SO_DEBUG
    Enable socket debugging. Only allowed for processes
    with the CAP_NET_ADMIN capability or an effective user id of 0.

    SO_REUSEADDR
    Indicates that the rules used in validating addresses supplied
    in a bind(2) call should allow reuse of local addresses. For
    PF_INET sockets this means that a socket may bind, except when
    there is an active listening socket bound to the address. When the
    listening socket is bound to INADDR_ANY with a specific port
    then it is not possible to bind to this port for any local address.

    SO_TYPE
    Gets the socket type as an integer (like SOCK_STREAM). Can be
    only read with getsockopt.

    SO_DONTROUTE
    Don't send via a gateway, only send to directly connected
    hosts. The same effect can be achieved by setting the
    MSG_DONTROUTE flag on a socket send(2) operation. Expects an
    integer boolean flag.

    SO_BROADCAST
    Set or get the broadcast flag. When enabled, datagram sockets
    receive packets sent to a broadcast address and they are allowed
    to send packets to a broadcast address. This option has no
    effect on stream-oriented sockets.

    SO_SNDBUF
    Sets or gets the maximum socket send buffer in bytes. The
    default value is set by the wmem_default sysctl and the maximum
    allowed value is set by the wmem_max sysctl.

    SO_RCVBUF
    Sets or gets the maximum socket receive buffer in bytes. The
    default value is set by the rmem_default sysctl and the maximum
    allowed value is set by the rmem_max sysctl.

    SO_LINGER
    Sets or gets the SO_LINGER option. The argument is a linger
    structure.

    struct linger {
    int l_onoff; /* linger active */
    int l_linger; /* how many seconds to linger for */
    };

    When enabled, a close(2) or shutdown(2) will not return until all
    queued messages for the socket have been successfully sent or
    the linger timeout has been reached. Otherwise, the call returns
    immediately and the closing is done in the background. When the
    socket is closed as part of exit(2), it always lingers in the
    background.

    SO_PRIORITY
    Set the protocol-defined priority for all packets to be sent on
    this socket. Linux uses this value to order the networking
    queues: packets with a higher priority may be processed first
    depending on the selected device queueing discipline. For ip(7),
    this also sets the IP type-of-service (TOS) field for outgoing
    packets.

    SO_ERROR
    Get and clear the pending socket error. Only valid as a
    getsockopt.
    Expects an integer.


    SIGNALS
    When writing onto a connection-oriented socket that has been shut
    down (by the local or the remote end) SIGPIPE is sent to the writing
    process and EPIPE is returned. The signal is not sent when the write
    call specified the MSG_NOSIGNAL flag.

    When requested with the FIOCSETOWN fcntl or SIOCSPGRP ioctl, SIGIO
    is sent when an I/O event occurs. It is possible to use poll(2) or
    select(2) in the signal handler to find out which socket the event
    occurred on. An alternative (in Linux 2.2) is to set a realtime signal
    using the F_SETSIG fcntl; the handler of the real time signal will be
    called with the file descriptor in the si_fd field of its siginfo_t.
    See fcntl(2) for more information.

    Under some circumstances (e.g. multiple processes accessing a single
    socket), the condition that caused the SIGIO may have already
    disappeared when the process reacts to the signal. If this
    happens, the process should wait again because Linux will resend the
    signal later.

    SYSCTLS
    The core socket networking sysctls can be accessed
    using the /proc/sys/net/core/* files or with the sysctl(2) interface.

    rmem_default
    contains the default setting in bytes of the socket receive buffer.

    rmem_max
    contains the maximum socket receive buffer size in bytes which a
    user may set by using the SO_RCVBUF socket option.

    wmem_default
    contains the default setting in bytes of the socket send buffer.

    wmem_max
    contains the maximum socket send buffer size in bytes which a
    user may set by using the SO_SNDBUF socket option.

    message_cost and message_burst
    configure the token bucket filter used to load limit warning
    messages caused by external network events.

    netdev_max_backlog
    Maximum number of packets in the global input queue.

    optmem_max
    Maximum length of ancillary data and user control data like the
    iovecs per socket.

    IOCTLS
    These ioctls can be accessed using ioctl(2):

    error = ioctl(ip_socket, ioctl_type, &value_result);

    SIOCGSTAMP
    Return a struct timeval with the receive timestamp of the last
    packet passed to the user. This is useful for accurate round trip
    time measurements. See setitimer(2) for a description of struct
    timeval.

    SIOCSPGRP
    Set the process or process group to send SIGIO or SIGURG signals
    to when an asynchronous I/O operation has finished or urgent
    data is available. The argument is a pointer to a pid_t. If the
    argument is positive, send the signals to that process. If the
    argument is negative, send the signals to the process group
    with the id of the absolute value of the argument. The process
    may only choose itself or its own process group to receive
    signals unless it has the CAP_KILL capability or an effective UID
    of 0.

    FIOASYNC
    Change the O_ASYNC flag to enable or disable asynchronous IO
    mode of the socket. Asynchronous IO mode means that the
    SIGIO signal or the signal set with F_SETSIG is raised when a new
    I/O event occurs.

    Argument is a integer boolean flag.

    SIOCGPGRP
    Get the current process or process group that receives SIGIO or
    SIGURG signals, or 0 when none is set.

    Valid fcntls:

    FIOCGETOWN
    The same as the SIOCGPGRP ioctl.
    signals, or 0 when none is set.

    Valid fcntls:

    FIOCGETOWN
    The same as the SIOCGPGRP ioctl.

    FIOCSETOWN
    The same as the SIOCSPGRP ioctl

    NOTES
    Linux assumes that half of the send/receive buffer is used for internal
    kernel structures; thus the sysctls are twice what can be observed on
    the wire.

    BUGS
    The CONFIG_FILTER socket options SO_ATTACH_FILTER and
    SO_DETACH_FILTER are not documented. The suggested interface to
    use them is via the libpcap library.

    VERSIONS
    SO_BINDTODEVICE was introduced in Linux 2.0.30. SO_PASSCRED is
    new in Linux 2.2. The sysctls are new in Linux 2.2.

    AUTHORS
    This man page was written by Andi Kleen.

    SEE ALSO
    socket(2), ip(7), setsockopt(2), getsockopt(2), packet(7), ddp(7)

    Linux Man Page 1999-05-07 SOCKET(7)
    [EDIT]

    J'ai reformatté un peu le texte.

    De plus, la partie qui nous intéresse est plus spécifiquement les IOCTL avec FIOASYNC + les SIGNALS avec FIOCSETOWN

    [/EDIT]

Discussions similaires

  1. Socket, recv et select qui ne marche pas
    Par Zapan dans le forum Réseau
    Réponses: 18
    Dernier message: 30/06/2006, 20h19
  2. [socket RAW] sendto ne marche pas !
    Par poporiding dans le forum C++
    Réponses: 4
    Dernier message: 18/01/2006, 13h14
  3. Socket qui ne marche pas
    Par Guillaume602 dans le forum C++
    Réponses: 4
    Dernier message: 15/01/2006, 14h07
  4. [ Problème ] .htaccess qui ne marche pas "partout"
    Par nnet_mathieu dans le forum Apache
    Réponses: 8
    Dernier message: 22/11/2005, 19h34
  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