Problème envoi chaine binaire: send() s'arrête sur le premier '\0' rencontré [Résolu]

Signaler
Messages postés
18
Date d'inscription
mercredi 28 janvier 2009
Statut
Membre
Dernière intervention
22 juillet 2011
-
Messages postés
1309
Date d'inscription
samedi 31 janvier 2009
Statut
Membre
Dernière intervention
5 juin 2013
-
Salut tout le monde..
Là je tente d'envoyer une image (simple exemple) avec send(), une image étant un fichier binaire elle contient des caractère non-imprimable tel que le '\0' (caractère nul) et là mon send() s'arrête sur le premier '\0' rencontré.
quelqu'un a une solution ?
(à part recourir à un encodage base64 ou quelque chose de semblable).

Merci d'avance.

:: un simple curieux ::

7 réponses

Messages postés
1309
Date d'inscription
samedi 31 janvier 2009
Statut
Membre
Dernière intervention
5 juin 2013
12
Salut,

Je serai curieux de voir ton code, en particulier la manière donc tu calcules la longueur de la chaîne à envoyer. Si tu utilises un strlen() pour calculer cette longueur alors il est parfaitement normal que ça s'arrête au premier \0 rencontré.
Messages postés
18
Date d'inscription
mercredi 28 janvier 2009
Statut
Membre
Dernière intervention
22 juillet 2011

Merci!! en faite j'utilisai strlen() pour spécifier la taille des données à envoyer, là je donne comme paramètre la taille de mon fichier et ça marche!!
Merci encore

Voici ma fonction envoi_fichier, si vous avez des remarques pour
Messages postés
18
Date d'inscription
mercredi 28 janvier 2009
Statut
Membre
Dernière intervention
22 juillet 2011

Merci!! en faite j'utilisai strlen() pour spécifier la taille des données à envoyer, là je donne comme paramètre la taille de mon fichier et ça marche!!
Merci encore

Voici ma fonction envoi_fichier, si vous avez des remarques pour l'améliorer:

int envoi_fichier(SOCKET sur_socket, char* fichier)
{
    FILE *p_fichier;

    p_fichier = fopen(fichier, "rb");
        if (p_fichier == NULL) return 0;
            puts("\n\touverture fichier source");
            int longueur = 0;
            while (!feof(p_fichier))
            {
                fgetc(p_fichier);
                longueur++;
            }
    fclose(p_fichier);

    printf("\n\ttaille fichier: %d", longueur);
    unsigned char* contenu_fichier;
    contenu_fichier = malloc(longueur*sizeof(char));
    puts("\n\tinitialisation conteneur");
    int i;
    for(i=0; i<longueur+1; i++) contenu_fichier[i]= '\0';

    p_fichier = fopen(fichier, "rb");
        if (p_fichier == NULL) return 0;
        i=0;
        while (!feof(p_fichier))
        {
            contenu_fichier[i] = fgetc(p_fichier);
            i++;
        }
    fclose(p_fichier);

    char t_donnees_a_envoyer[10] = {0};
    sprintf(t_donnees_a_envoyer, "%d", longueur);
    if(send(sur_socket, t_donnees_a_envoyer, strlen(t_donnees_a_envoyer), 0) == SOCKET_ERROR) return 0;
    if(send(sur_socket, &t_donnees_a_envoyer[strlen(t_donnees_a_envoyer)+1], 1, 0) == SOCKET_ERROR) return 0;
    if(send(sur_socket, contenu_fichier, longueur ,0) == SOCKET_ERROR) return 0;

    free(contenu_fichier);
    return 1;
}
Messages postés
1309
Date d'inscription
samedi 31 janvier 2009
Statut
Membre
Dernière intervention
5 juin 2013
12
Merci encore

De rien ;)

si vous avez des remarques pour l'améliorer

Oui, mapper le fichier en mémoire est bien plus efficace. A noter que mmap() n'existe aps sous windows, il temfaudra regarder les différentes documentation pour trouver un équivalent (j'ai connais un pour le C++ sous windows mais pas pour le C).

Un exemple d'implémentation sur un système GNU/Linux :
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include 
#include <stdio.h>
#include <fcntl.h>

int             send_file(int so, const char *file)
{
  struct stat   st;
  int           fd;
  int           nbw;
  char          *addr;

  fd = open(file, O_RDONLY);
  if (fd == -1)
    {
      perror("open");
      return -1;
    }
  fstat(fd, &st);
  addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  if (addr == MAP_FAILED)
    {
      perror("mmap");
      return -1;
    }
  nbw = send(so, addr, st.st_size, 0);
  if (nbw != st.st_size)
    {
      perror("send");
      munmap(addr, st.st_size);
      return -1;
    }
  return munmap(addr, st.st_size);
}
Messages postés
1309
Date d'inscription
samedi 31 janvier 2009
Statut
Membre
Dernière intervention
5 juin 2013
12
Errata: j'ai oublié le close() (à ajouter juste après le mmap().

Avec les lignes précédentes et suivantes ça donne :
  /* ... */
  addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  close(fd);
  if (addr == MAP_FAILED)
  /* ... */
Messages postés
18
Date d'inscription
mercredi 28 janvier 2009
Statut
Membre
Dernière intervention
22 juillet 2011

Re TychoBrahe.
Désolé pour mon retard. je suis un peu débordé ces derniers temps .
Je vais essayer de trouver une équivalente sous Windows. en attendant ça consiste en quoi "mapper le fichier en mémoire"
Dslé encore et Merciii
Messages postés
1309
Date d'inscription
samedi 31 janvier 2009
Statut
Membre
Dernière intervention
5 juin 2013
12
Salut,

en attendant ça consiste en quoi "mapper le fichier en mémoire"

Tout simplement à le charger dans la mémoire afin d'y avoir directement accès. Bref, tu récupère un pointeur vers un espace mémoire contenant le fichier. Pour caricaturer, c'est un peu comme un gros malloc dans lequel on copie le fichier. La différence la plus notable est que mmap est bien plus "intelligent" (optimisation de l'utilisation réel de la mémoire etc).

Quelques liens :
mmap() sur Wikipedia
man 2 mmap