Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2658 connectés 

  FORUM HardWare.fr
  Programmation
  C

  Pb Socket et fichier

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Pb Socket et fichier

n°1261226
xelad
Posté le 07-12-2005 à 18:53:24  profilanswer
 

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
mood
Publicité
Posté le 07-12-2005 à 18:53:24  profilanswer
 

n°1261273
Sve@r
Posté le 07-12-2005 à 21:14:58  profilanswer
 

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
n°1261300
xelad
Posté le 07-12-2005 à 22:17:18  profilanswer
 

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...

n°1261344
Sve@r
Posté le 07-12-2005 à 23:06:10  profilanswer
 

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
n°1261364
xelad
Posté le 07-12-2005 à 23:53:16  profilanswer
 

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

n°1261378
xelad
Posté le 08-12-2005 à 00:48:31  profilanswer
 

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
n°1261429
Sve@r
Posté le 08-12-2005 à 06:50:48  profilanswer
 

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.
n°1264718
xelad
Posté le 12-12-2005 à 17:12:32  profilanswer
 

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++++++++++

n°1265349
Sve@r
Posté le 13-12-2005 à 11:46:01  profilanswer
 

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.
n°1265369
xelad
Posté le 13-12-2005 à 12:04:18  profilanswer
 

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

mood
Publicité
Posté le 13-12-2005 à 12:04:18  profilanswer
 

n°1266443
xelad
Posté le 14-12-2005 à 15:57:14  profilanswer
 

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. }

n°1266448
xelad
Posté le 14-12-2005 à 15:58:58  profilanswer
 

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
n°1266453
xelad
Posté le 14-12-2005 à 16:01:10  profilanswer
 

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.


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

  Pb Socket et fichier

 

Sujets relatifs
Gestion des données d'un fichier TXTsupprimer un fichier sous unix
script tranférer dans un fichier[c++] DLL fichier de logs
lire et écrire à partir d'un fichierRécupérer les infos d'un fichier txt en batch
fichier HEXLecture d'un fichier texte en boucle C++
Locker un fichierEcrire un fichier texte sur un serveur distant
Plus de sujets relatifs à : Pb Socket et fichier


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR