Pb Socket et fichier

Pb Socket et fichier - C - Programmation

Marsh Posté le 07-12-2005 à 18:53:24    

Bonsoir,
 
J'ai un souci avec un probleme de socket pour envoyer un fichier binaire entre 1 serveur en C et un client Java.
Le but et d'envoyer un fichier JPG à la demande du client Java.
 
Voici le code permettant l'envoi du fichier capture.jpg :
 

Code :
  1. int SIZE=1024;
  2. int j;
  3. size_t nb_lu;
  4. FILE *fichier_a_envoyer;
  5. FILE *fichier_socket=fdopen(msgsock,"w" );
  6. char *chaine=(char *)malloc(sizeof(char)*SIZE);
  7. fichier_a_envoyer=fopen("capture.jpg","r" );
  8. if(fichier_a_envoyer){
  9.  while((nb_lu=fread(chaine,1,SIZE,fichier_a_envoyer))>0){
  10.   for(j=0;j<nb_lu;j++) printf("%o\n",chaine[j]);
  11.   fwrite(chaine, nb_lu, 1, fichier_socket);
  12.  }
  13.  send(msgsock,fichier_socket,sizeof(fichier_socket),0);
  14.  fclose(fichier_a_envoyer);
  15.  fclose(fichier_socket);
  16.  free(chaine);
  17. }


 
Le problème (accrochez-vous...) c'est qu'il y a 4 octets qui sont ajoutés comme par magie au début du dernier bloc, c'est à dire qui si le fichier fait 1030o par ex, le client va recevoir 1034o avec les blocs suivant : [1024, 10] au lieu de [1024, 6]. Il faut préciser aussi que les 4 octets en question sont toujours identiques en valeur. Pour les tests, j'ai mis HELLO dans capture.jpg, la sortie du printf("%o\n",chaine[j]); correspond bien au code ASCII de HELLO donc le "fichier_a_envoyer" semble bon.
 
Si vous avez une idée de test pour isoler plus précisement le pb ou carrément la solution... merci pour vos réponses.

Message cité 1 fois
Message édité par xelad le 08-12-2005 à 00:49:34
Reply

Marsh Posté le 07-12-2005 à 18:53:24   

Reply

Marsh Posté le 07-12-2005 à 21:14:58    

xelad a écrit :

Bonsoir,
 
J'ai un souci avec un probleme de socket pour envoyer un fichier binaire entre 1 serveur en C et un client Java.
Le but et d'envoyer un fichier JPG à la demande du client Java.
 
Voici le code permettant l'envoi du fichier capture.jpg :
 

Code :
  1. int SIZE=1024;
  2. int j;
  3. size_t nb_lu;
  4. FILE *fichier_a_envoyer;
  5. FILE *fichier_socket=fdopen(msgsock,"w" );
  6. char *chaine=(char *)malloc(sizeof(char)*SIZE);
  7. fichier_a_envoyer=fopen("capture.jpg","r" );
  8. if(fichier_a_envoyer){
  9.  while((nb_lu=fread(chaine,1,SIZE,fichier_a_envoyer))>0){
  10.   for(j=0;j<nb_lu;j++) printf("%o\n",chaine[j]);
  11.   fwrite(chaine, nb_lu, 1, fichier_socket);
  12.  }
  13.  send(msgsock,fichier_a_envoyer,sizeof(fichier_a_envoyer),0);
  14.  fclose(fichier_a_envoyer);
  15.  fclose(fichier_socket);
  16.  free(chaine);
  17. }


 
Le problème (accrochez-vous...) c'est qu'il y a 4 octets qui sont ajoutés comme par magie au début du dernier bloc, c'est à dire qui si le fichier fait 1030o par ex, le client va recevoir 1034o avec les blocs suivant : [1024, 10] au lieu de [1024, 6]. Il faut préciser aussi que les 4 octets en question sont toujours identiques en valeur. Pour les tests, j'ai mis HELLO dans capture.jpg, la sortie du printf("%o\n",chaine[j]); correspond bien au code ASCII de HELLO donc le "fichier_a_envoyer" semble bon.
 
Si vous avez une idée de test pour isoler plus précisement le pb ou carrément la solution... merci pour vos réponses.


 
Hum... quand tu fais "send(msgsock, fichier_a_envoyer, sizeof(fichier_a_envoyer), 0)"; tu envoies sur ta socket une variable de type "FILE *"  et la fonction "send" (qui envoie le pointé de ce qu'on lui passe) va envoyer benoitement le contenu de la structure "FILE" (qui doit sûrement commencer par 4 octets bien particuliers...)  :heink:  
Bon, tu y envoies ce que tu veux sur ta socket... mais moi j'aurais plutôt fait "send(msgsock, chaine, nb_lu, 0)"   :sol:
 
Idée de test ? T'as qu'à afficher la valeur hexa des 4 premiers octets de "*fichier_a_envoyer"


Message édité par Sve@r le 07-12-2005 à 22:10:54
Reply

Marsh Posté le 07-12-2005 à 22:17:18    

merci sve@r,
 
Le probleme doit se situer dans les environs en effet. mais comme il s'agit de l'envoi d'un fichier binaire apprement on est obligé de passer par "FILE *fichier_socket=fdopen(msgsock,"w" );" sinon d'apres ce que j'ai cru comprendre dans d'autres topics y'a des problemes avec des \n attendus qu'il n'y a pas dans les fichiers binaires. Je vais essayer quand meme...

Reply

Marsh Posté le 07-12-2005 à 23:06:10    

xelad a écrit :

merci sve@r,
 
Le probleme doit se situer dans les environs en effet. mais comme il s'agit de l'envoi d'un fichier binaire apprement on est obligé de passer par "FILE *fichier_socket=fdopen(msgsock,"w" );" sinon d'apres ce que j'ai cru comprendre dans d'autres topics y'a des problemes avec des \n attendus qu'il n'y a pas dans les fichiers binaires. Je vais essayer quand meme...


 
Pas du tout !!!
Tu ouvres ton "capture.jpg" en mode "rb" et c'est tout. De plus je ne sais pas à quoi sert "fdopen()" mais je m'en suis jamais servi pour transférer des infos via socket...
 
T'as qq exemples simples sur ce document http://fr.lang.free.fr/cours/SocketCsyst_v1.0.pdf


Message édité par Sve@r le 07-12-2005 à 23:16:25
Reply

Marsh Posté le 07-12-2005 à 23:53:16    

Merci je suis en train de lire le pdf....

Reply

Marsh Posté le 08-12-2005 à 00:48:31    

Bon bah j'ai beau tout essayer j'ai toujours 4 octets de trop, et toujours les memes.

Message cité 1 fois
Message édité par xelad le 08-12-2005 à 00:48:42
Reply

Marsh Posté le 08-12-2005 à 06:50:48    

xelad a écrit :

Bon bah j'ai beau tout essayer j'ai toujours 4 octets de trop, et toujours les memes.


 
Essaye ce code:

#include <sys/types.h>      /* Types prédéfinis "c" */
#include <sys/socket.h>      /* Généralités sockets */
#include <sys/param.h>      /* Paramètres et limites système */
#include <netinet/in.h>      /* Spécifications socket internet */
#include <stdio.h>       /* I/O fichiers classiques */
#include <string.h>      /* Gestion chaines de caractères */
#include <netdb.h>      /* Gestion network database */
#include <errno.h>       /* Erreurs système */
 
#define SERVEUR_DEFAULT  ("localhost" )   /* Nom serveur utilisé par défaut */
#define SERVICE_LABEL  ("essai" )    /* Nom service requis */
#define SERVICE_PROTOCOL  ("tcp" )    /* Protocole service requis */
#define SZ_BUF   (256)    /* Taille buffer */
 
int main(
 int argc,        /* Nbre arg. */
 char *argv[])      /* Ptr arguments */
{
 /* Déclaration des variables */
 ushort i;       /* Indice de boucle */
 ushort j;       /* Indice de boucle */
 
 int sk_connect;      /* Socket de connection */
 int sk_dialog;      /* Socket de dialogue */
 
 char buf[SZ_BUF];      /* Buffer texte */
 char hostname[MAXHOSTNAMELEN + 1];   /* Nom machine locale */
 char *serveur;      /* Ptr vers le nom du serveur */
 char *pt;       /* Ptr vers un caractère qcq. */
 
 struct sockaddr_in adr_serveur;    /* Adresse socket serveur */
 struct hostent *host_info;     /* Info. host */
 struct servent *service_info;    /* Info. service demandé */
 
 /* Remplissage du nom du serveur */
 if (argc > 1)
  /* Le nom du serveur est l'argument n° 1 */
  serveur=argv[1];
 else
  /* Le nom du serveur est pris par défaut */
  serveur=SERVEUR_DEFAULT;
 
 /* Récuperation nom machine locale (juste pour l'exemple) */
 if (gethostname(hostname, MAXHOSTNAMELEN) != 0)
 {
  fprintf(stderr, "ligne %u - gethostname(%s) - %s\n", __LINE__, hostname, strerror(errno));
  exit(errno);
 }
 printf("gethostname='%s'\n", hostname);
 
 /* Récuperation informations serveur */
 if ((host_info=gethostbyname(serveur)) == NULL)
 {
  fprintf(stderr, "ligne %u - gethostbyname(%s) - %s\n", __LINE__, serveur, strerror(errno));
  exit(errno);
 }
 fputc('\n', stdout);
 printf("host_info.h_name='%s'\n", host_info->h_name);
 for (i=0; host_info->h_aliases[i] != NULL; i++)
  printf("host_info.h_aliase[%hu]='%s'\n", i, host_info->h_aliases[i]);
 printf("host_info.h_addrtype=%u\n", host_info->h_addrtype);
 printf("host_info.h_length=%u\n", host_info->h_length);
 for (i=0; host_info->h_addr_list[i] != NULL; i++)
 {
  printf("host_info.h_addr_list[%hu]=", i);
  for (j=0; j < host_info->h_length; j++)
   printf("%hu ", (unsigned char)host_info->h_addr_list[i][j]);
  fputc('\n', stdout);
 }
 
 /* Récuperation port dans "/etc/services" */
 if ((service_info=getservbyname(SERVICE_LABEL, SERVICE_PROTOCOL)) ==NULL)
 {
  fprintf(stderr, "ligne %u - getservbyname(%s, %s) - %s\n", __LINE__, SERVICE_LABEL, SERVICE_PROTOCOL, strerror(errno));
  exit(errno);
 }
 fputc('\n', stdout);
 printf("service_name='%s'\n", service_info->s_name);
 for (i=0; service_info->s_aliases[i] != NULL; i++)
  printf("service_s_aliase[%hu]='%s'\n", i, service_info->s_aliases[i]);
 printf("service_port=%hu\n", ntohs(service_info->s_port));
 printf("service_protocole='%s'\n", service_info->s_proto);
 
 /* Remplissage adresse socket */
 memset(&adr_serveur, 0, sizeof(struct sockaddr_in));
 adr_serveur.sin_len=host_info->h_length;
 adr_serveur.sin_family=AF_INET;
 adr_serveur.sin_port=service_info->s_port;
 memcpy(&adr_serveur.sin_addr.s_addr, host_info->h_addr, host_info->h_length);
 
 /* Tentative de connection en boucle permanente */
 fputc('\n', stdout);
 do {
  /* Création socket */
  if ((sk_dialog=socket(AF_INET, SOCK_STREAM, 0)) == (-1))
  {
   fprintf(stderr, "ligne %u - socket() - %s\n", __LINE__, strerror(errno));
   exit(errno);
  }
 
  /* Connection au serveur */
  if ((sk_connect=connect(sk_dialog, &adr_serveur, sizeof(struct sockaddr_in))) == (-1))
  {
   fprintf(stderr, "ligne %u - connect() - %s\n", __LINE__, strerror(errno));
   sleep(5);
  }
 } while (sk_connect == (-1));
 printf("Connection réussie\n" );
 
 /* Saisie et envoi de la chaîne en boucle */
 do {
  /* Saisie de la chaîne */
  fputs("Entrer chaine (EOT pour finir) :", stdout); fflush(stdout);
  fgets(buf, SZ_BUF, stdin);
 
  /* Suppression de la chaîne saisie du caractère '\n' s'il y est */
  if ((pt=strchr(buf, '\n')) != NULL)
   *pt='\0';
 
  /* Envoi de la chaîne sur la socket */
  if (write(sk_dialog, buf, strlen(buf) + 1) == (-1))
   fprintf(stderr, "ligne %u - write(%s) - %s\n", __LINE__, buf, strerror(errno));
 } while (strcmp(buf, "EOT" ) != 0);
 
 /* Fermeture socket et fin du programme */
 close(sk_dialog);
 return(0);
}


 
C'est un client destiné à communiquer avec un serveur via un n° de port défini dans le fichier "/etc/services" sous le label "essai/tcp"
Il attend un argument qui est le nom du serveur mais prend "localhost" par défaut
Une fois le client connecté sur le serveur, il attend une chaîne et l'envoie au serveur. Normallement, le serveur associé est censé attendre un client et afficher ensuite la chaîne reçue.
Le client s'arrête dès qu'on tape la chaine "EOT"
 
Ptet que tu devras l'adapter un peu (je suis pas certain que la structure "hostent" contienne un membre "h_length" sous Linux) mais il fonctionne.
Moi j'utilisais "write" pour envoyer mes infos au serveur mais tu peux utiliser "send" si t'en as envie...


Message édité par Sve@r le 08-12-2005 à 06:54:32

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 12-12-2005 à 17:12:32    

Merci pour toutes ces réponses Sve@r. Mon binome qui travaille sur le client Java à "contourné" le probleme en extrayant les 4 octets en question après la récéption du fichier. C'est pas terrible mais ça marche maintenant. Merci encore
A++++++++++

Reply

Marsh Posté le 13-12-2005 à 11:46:01    

xelad a écrit :

Merci pour toutes ces réponses Sve@r. Mon binome qui travaille sur le client Java


Tu veux dire "serveur Java"  !!!
 

xelad a écrit :

à "contourné" le probleme en extrayant les 4 octets en question après la récéption du fichier. C'est pas terrible mais ça marche maintenant. Merci encore
A++++++++++


 
Euh... très dangereux ce truc !!! Si l'erreur vient d'un bug de ton code, le bug est resté !!!
C'est comme si on soignait un bras cassé en donnant des anti-douleurs... la douleur disparait mais le bras reste cassé !!!
 
Passe-moi via msg privé le code complet de ton client. Je le compilerai et le mettrai en dialogue avec mon serveur voir ce qu'il reçoit...


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 13-12-2005 à 12:04:18    

En fait c'est le serveur qui est en C, je m'explique :
Le but du projet (scolaire) est de faire un serveur qui créé des screenshots à la demande du client. Le serveur reçoit une demande de screenshot, créé le screenshot et l'envoie au client java. C'est donc bien le serveur qui est en C puisqu'il reste tout le temps 'à l'écoute'.
Je te poste mon code ce soir (je l'ai pas sous la main), meme si le projet est terminé (en bricolant coté client, c'est vraiment pas terrible, tu as raison) j'aimerai bien savoir ce qui se passe...
Merci

Reply

Marsh Posté le 13-12-2005 à 12:04:18   

Reply

Marsh Posté le 14-12-2005 à 15:57:14    

Le fichier main_server.c
 

Code :
  1. #include "mod_datagram_srv.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #include <string.h>
  8. #include <unistd.h>
  9. void bzero();
  10. int read();
  11. int write();
  12. int main(){
  13.   int sock, msgsock;
  14.   size_t length;
  15.   socklen_t lemis;
  16.   struct sockaddr_in name;
  17.   struct sockaddr_in emis;
  18.   char buf[1024];
  19.   int rval,i;
  20.   /*creation de la socket AF_INET entre machine*/
  21.   sock=socket(AF_INET,SOCK_STREAM,0);
  22.   /*initialisation de la socket*/
  23.   bzero(&name,sizeof(name));
  24.   lemis=sizeof(emis);
  25.   bzero(&emis,lemis);
  26.   name.sin_family=AF_INET;
  27.   name.sin_addr.s_addr=INADDR_ANY;
  28.   name.sin_port=htons(9999);
  29.   length=sizeof(name);
  30.  
  31.   bind(sock,(struct sockaddr *)&name,length);
  32.     printf("socket serveur TCP port #%d\n",
  33. ntohs(name.sin_port));
  34.   listen(sock,5);
  35.   do{
  36.     msgsock=accept(sock,(struct sockaddr *)&emis,&lemis);
  37.     if(msgsock<0){
  38.       perror("accept\n" );
  39.     }
  40.     else do{
  41.      if (getsockname(msgsock,(struct sockaddr *)&emis,&lemis)<0){
  42. perror ("getsockname" );
  43.         close(sock);
  44. return 1;
  45. }
  46.       //mise a zero du buffer
  47.       bzero(buf,sizeof(buf));
  48.      
  49.       if ((rval=read(msgsock,buf,1024))<0){
  50. perror("read" );
  51. i=1;
  52.       }
  53.       i=0;
  54.       if(rval==0){
  55. fprintf(stderr,"fin connexion\n" );
  56.       }
  57.       else{
  58. interpreter_datagram(buf,msgsock);
  59. rval=0;
  60.       }
  61.     }
  62.    
  63.     while(rval!=0);
  64.     close (msgsock);
  65.     printf("\nFin de connexion\n" );
  66.   }
  67.   while(1);
  68. }

Reply

Marsh Posté le 14-12-2005 à 15:58:58    

Le fichier mod_datagram_srv.h
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <sys/socket.h>
  5. #include <netinet/in.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. char *tab[4];
  9. void DMDSCR();
  10. void FINCOM();
  11. void INCONNU();
  12. int decomposer_datagram();
  13. void interpreter_datagram();
  14. void ajouter_champs();
  15. char *fincom();
  16. char *demande();
  17. char *init_datagram();
  18. char *str_sub();
  19. void DMDSCR(const char *datagram,int msgsock){
  20. int SIZE=1024;
  21. printf("demande d'envoi d'un screenshot\n" );
  22. // make screenshot
  23. // system("import -window root capture.jpg -quality 25" );
  24. //SP
  25. int j;
  26. size_t nb_lu;
  27. FILE *fichier_a_envoyer;
  28. FILE *fichier_socket=fdopen(msgsock,"w" );
  29. char *chaine=(char *)malloc(sizeof(char)*SIZE);
  30. //SP
  31. //memset(chaine,'\0',sizeof(chaine));
  32. fichier_a_envoyer=fopen("capture.jpg","r" );
  33. if(fichier_a_envoyer){
  34.     while((nb_lu=fread(chaine,1,SIZE,fichier_a_envoyer))>0){
  35.    
  36.  for(j=0;j<nb_lu;j++) printf("%o\n",chaine[j]);
  37.     if (nb_lu!=SIZE){
  38.  fwrite(str_sub(chaine,4,nb_lu), nb_lu-4, 1, fichier_socket);
  39.     }
  40.     else fwrite(chaine, nb_lu, 1, fichier_socket);
  41.     }
  42. }else printf("Pas de fichier" );
  43. send(msgsock,fichier_socket,sizeof(fichier_socket),0);
  44. fclose(fichier_a_envoyer);
  45. fclose(fichier_socket);
  46. free(chaine);
  47. }
  48. char *str_sub(const char *s, unsigned int start, unsigned int end){
  49.     char *new_s=NULL;
  50.     if(s && start < end){
  51.         new_s=malloc(sizeof(*new_s)*(end-start+2));
  52.         int i;
  53. for (i=start; i<=end; i++) new_s[i-start]=s[i];
  54.     }
  55.     return new_s;
  56. }
  57. // SCINDE LE DATAGRAM data DANS UN TABLEAU tab
  58. int decomposer_datagram(char *data,char *tab[]){
  59. char *p;
  60. int i=0;
  61. p=(char *)strtok(data,"&&" );
  62. while(p != NULL){
  63.  tab[i]=p;
  64.  p=(char *)strtok(NULL,"&&" );
  65.  i++;
  66. }
  67. i--;
  68. return i;
  69. }
  70. void interpreter_datagram(const char *datagram,int msgsock){
  71. char *code=(char *)malloc(sizeof(char)*7);
  72. code=strncpy(code,datagram,sizeof(char)*6);
  73. code[6]='\0';
  74. printf("\n\n----RECEPTION TRAME : --> %s \nORDRE : %s\n",datagram,code);
  75. if(strcmp(code,"DMDSCR" )==0) DMDSCR(datagram,msgsock);
  76. else if(strcmp(code,"FINCOM" )==0) FINCOM(datagram,msgsock);
  77. else INCONNU(datagram);
  78. free(code);
  79. }
  80. // ALLOUE UN CHAMPS DE DATAGRAM
  81. void ajouter_champs(char *data, const char *champs){
  82. strcat(data,"&&" );
  83. strcat(data,champs);
  84. }
  85. // FABRIQUE UNE FIN DE COMMUNICATION
  86. char *fincom(){
  87. char *data=(char *)malloc(sizeof(char)*7);
  88. strcpy(data,"FINCOM" );
  89. return data;
  90. }
  91. // FABRIQUE UNE DEMANDE
  92. char *demande(const char *code){
  93. char *data=(char *)malloc(sizeof(char)*7);
  94. strcpy(data,code);
  95. return data;
  96. }
  97. // INITIALSIE UN DATAGRAM
  98. char *init_datagram(const char *code){
  99. char *data=(char *)malloc(sizeof(char)*100);
  100. strcpy(data,code);
  101. return data;
  102. }
  103. void INCONNU(const char *datagram){
  104. printf("Code inconnu\n" );
  105. }
  106. void FINCOM(const char *datagram, int msgsock){
  107.     char *reponse;
  108.     reponse=fincom();
  109.     send(msgsock,reponse,strlen(reponse),0);
  110.     free(reponse);
  111. }


Message édité par xelad le 14-12-2005 à 19:05:39
Reply

Marsh Posté le 14-12-2005 à 16:01:10    

J'avais fait ce code pour faire un serveur qui executait des requetes SQL et qui formatait les réponses pour les renvoyer à un client C. Je l'ai réutilisé pour ce nouveau projet.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed