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 :

[socket] Pb send() et recv()


Sujet :

C++

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    309
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 309
    Points : 148
    Points
    148
    Par défaut [socket] Pb send() et recv()
    Salut,

    J'implemente une classe pour l'utilisation des sockets et mes premiers tests ne sont pas concluants. Le message que le serveur affiche est depourvu d'espaces et suivi de caracteres parasites plus ou moins bien reconnus par l'encodage. Voici le code pour l'envoi du message (c'est une classe dont le serveur et le client derive) :
    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
    bool SOCKET_INIT::envoi(std::string msg)
    {
    	const char *buf = msg.c_str();
    	int len = strlen(buf);
    	int err = send(desc_sock, buf, len, 0);
    	if(err == -1){
    		print_error("échec de l'envoi");
    		return false;
    	}else if(err != len){
    		print_error("message partiellement envoyé");
    		return false;
    	}
    	return true;
    }
     
    void SOCKET_INIT::recep(string msg, string addr)
    {
    	//à implémenter suivant les besoins
    	cout << addr << " > " << msg << endl;
    }
     
    void SOCKET_INIT::close()
    {
    	if(desc_sock != INVALID_SOCKET){
    		shutdown(desc_sock, 2); //ferme l'envoi et la reception
    	}
    }
     
    void SOCKET_INIT::print_error(string error)
    {
    	//à implementer suivant les besoins
    	cout << "ERREUR: " << error << endl;
    }
    Et voici le traitement du serveur :
    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
    void SOCKET_SERVER::ecoute()
    {
    	int error = listen(desc_sock, max_connexion);
     
    	if(error == -1){
    		print_error("impossible d'écouter sur le port");
    		return;
    	}
     
    	/**** acceptation d'un client ****/
    	int desc_new; //descripteur de la nouvelle connexion
    	socklen_t sin_size = sizeof(struct sockaddr_in);
    	desc_new = accept(desc_sock, (struct sockaddr *) &their_addr, &sin_size);
     
    	if(desc_new == -1){
    		print_error("connexion entrante refusée");
    		return;
    	}
     
    	while(true){
     
    		/**** réception du message ****/
    		char buffer[MAXDATASIZE];
    		int num_byte = recv(desc_new, buffer, MAXDATASIZE, 0);
     
    		if(num_byte == -1){
    			print_error("impossible de lire le message entrant");
    			return;
    		}
     
    		/**** traitement du message ****/
    		string addr = inet_ntoa(their_addr.sin_addr);
    		recep(buffer, addr);
    	}
    }
    Je pense que l'erreur provient de l'envoi. Je sais qu'en C on fait en general quelque chose comme ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    // créer le buffer pour copier la chaîne
    size_t size = message.size() + 1;
    char * buffer = new char[ size ];
    // copier la chaîne dans le buffer
    strncpy( buffer, message.c_str(), size );
    Mais je voudrais quelque chose qui soit du C++.

    Merci de me faire de vos remarques/conseils (ou autres).

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Tu ne transmets pas le zéro terminal (et d'après Emmanuel Delahaye, il ne faut pas le transmettre). Tu dois donc le rajouter côté serveur ou construire une string à partir de ton buffer et de la longueur recue.

  3. #3
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Je ne vois ce qui empêcherai le transfert d'un 0 à la fin de la chaine...
    Mais bon... quand on parle de strings il y a plusieurs choses:
    - Un 0 n'est pas *forcément* la fin d'une chaine (essayes en Shift-JIS par exemple). Il faut donc, comme dit Medinoc, ou bien spécifier la longueur de la châine *avant* l'envoi, ou bien spécifier le code-page, ou bien convenir d'un code-page prédéfini entre le client et le serveur (sachant que celui par défaut dans C++ n'est peut être pas le même).
    - D'autre part, rien ne force send() (on est en TCP là) à tout envoyer d'un coup... c'est une écriture bufferisée. Du coup si le client fait un send(aaa,1000) puis send(bbb,500).... et le serveur int len = recv(buffer,buffersize);, la seule restriction sur len est que: 0 < len <= buffersize
    ... len peut très bien valoir 1500 (les deux sends regroupés) ou 128 (le premier send coupé), etc....

    Il semble que tu ne prennes pas compte cette longueur reçue... (tu l'utilises juste pour tester une valeur d'erreur)

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    309
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 309
    Points : 148
    Points
    148
    Par défaut
    Je vois pas pourquoi j'ajouterais la fin de chaine au buffer de reception. Lorsque je declare
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char buffer[MAXDATASIZE];
    il a deja un caractere de fin chaine a la position MAXDATASIZE, non ? Pour moi, la fonction recv() ne fait que remplir avec des donnees l'espace memoire alloue a buffer. (Ce qui pourrait effectivement etre critique si recv() recevait MAXDATASIZE+1 caracteres ...)

    Admettons que send() envoie successivement 1000 puis 500 caracteres. recv() n'a aucun moyen de savoir que le message de 1500 caracteres qu'elle recoit est en fait un message de 1000 et un message de 500. A part envoyer la fin de chaine, je vois pas trop ce que je peux faire.

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    309
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 309
    Points : 148
    Points
    148
    Par défaut
    J'ai ajoute le zero au buffer et le code fonctionne... Donc apparemment ce n'est pas a la declaration du char que le zero est ajoute.

    Par contre, j'ai un autre probleme. Les espaces que contiennent les textes envoyes sont systematiquement supprimes alors que tous les caracteres (meme ceux ne faisant pas partie de la norme ASCII) fonctionnent.

  6. #6
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Oublie l'ASCII.... send et recv envoient du BINAIRE et rien d'autre... donc des octets, sans se préoccuper de ce qu'il y a dedans...

    Tu envoies des octets avec 0x20 ? Ca doit les recevoir de l'autre coté...
    Donc il doit y avoir un problême à la reception (voir à l'affichage... ca serait pas la première fois que c'est juste l'output de vérification qui merdoie ! ).

    Sinon char tableau[1000] déclare un tableau de 1000 chars sur la pile ... rien de plus...
    En gros, le processeur va juste modifier le pointeur de pile de 1000 octets... Si il y avait des 0 avant, tant mieux... si il y avait que des 0xCD... ben tu auras que du 0xCD !
    A toi de mettre le 0 sur le dernier octet: tableau[999] !

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    309
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 309
    Points : 148
    Points
    148
    Par défaut
    Ahah, je crois avoir localisé le problème. Ce petit bout de code de la fonction d'envoi,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const char *buf = msg.c_str();
    int len = strlen(buf);
    int err = send(desc_sock, buf, len, 0);
    cout << buf << endl;
    affiche le résultat suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    t t //valeur tapée
    t
    t
    Je crois qu'il comprend l'espace comme étant un retour à la ligne et que le socket fait 2 send(). Mais je sais pas trop comment faire pour empêcher cela.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Sur un socket : send et recv ou read et write ?
    Par Médinoc dans le forum Réseau
    Réponses: 35
    Dernier message: 05/11/2009, 15h51
  2. socket send et recv
    Par sebatlante dans le forum Réseau
    Réponses: 24
    Dernier message: 29/08/2007, 01h34
  3. Question sur les fonctions "send()" et "recv(
    Par damien99 dans le forum MFC
    Réponses: 6
    Dernier message: 10/02/2006, 20h47
  4. Socket et send();
    Par deviante dans le forum C++
    Réponses: 2
    Dernier message: 13/01/2006, 20h32

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