Problem transmission image BMP par socket C++

Résolu/Fermé
djerem06 Messages postés 46 Date d'inscription jeudi 5 juin 2008 Statut Membre Dernière intervention 23 avril 2015 - 28 juin 2009 à 16:43
djerem06 Messages postés 46 Date d'inscription jeudi 5 juin 2008 Statut Membre Dernière intervention 23 avril 2015 - 30 juin 2009 à 14:27
Bonjour a tous,

Je code un Client serveur.
le serveur en mode console, fair un imprime ecran, envoi la valeur entiére de la taille du fichier en octet, puis envoi l'image BMP capturé au client par packet de 512 octets. le serveur utilise les socket avec WSA, sockaddr_in etc...

le client en mode fénétre utilise wxwidget donc les socket simplifié wxSocketClient etc... ça c juste pour préciser.

voici le code de l'emission du fichier BMP (serveur):
//au préalable, taille est la variable entiére qui contient le nombre d'octet du fichier
{
char octet[512];
int re;
int i;
unsigned short int NbOctet=512;

for(i=0 ; i<((taille/NbOctet) + 1 ); i++){

re = read(idfichier, octet, NbOctet); //lecture de 512 octet dans le fichier

re = Classe.ecrireOctets(octet, re); //emission de ces 512 octet via une méthode d'une classe

}
}

voici le code de la réception du fichier BMP (client):

{
char octet[512];
unsigned long int i;
unsigned long int j;
unsigned long int NbOctet=512;

for(i=0 ; i < ((taille/NbOctet) + 1) ; i++){
Client.Socket->Read(octet, NbOctet); //vague de reception de 512 octets

for(j = i*NbOctet ; j < (i*NbOctet + NbOctet) ;j++){
//Client.contenu est une chaine d'octet qui va contenir tou le fichier
Client.contenu[j] = octet[j-i*NbOctet];
//ici, méme si lors de la derniere vague d'émission doctet il y en a moin de 512 et qu'on en
//ecri quand mm 512 dans contenu, c'est pas grave seul les tailles octets seront ecrit dans le
//nouveau fichier, pas un octet de plus.
}

}

Client.FaireUnFichier(taille); //sachant quand le contenu est un atribut public de la classe donc
//seul la taille est passé en paramétre de cette méthode.

}

alors je sais que ce code n'est pas du grand art, mais il fonctionne, lorsque je lance le serveur et le client sur mon méme PC, le transfére de l'image se déroule bien, et limage réstitué au Client est parfaite.
en revanche lors que le serveur se trouve sur une autre machine du réseau, la connexion se passe bien, le transfére de la taille de limage aussi, et le transfére de limage a premiére vue aussi, et pourtant, en ouvrant l'image BMP réstitué, celle-ci s'affiche exactement comme une certaine chaine télévision payante lorsqu'on ne l'a pas payé, c'est a dire toute les ligne entrelacé...
j'ai donc essayé de voir si le serveur lisais et éméttais réellement 512 octets a chaque vague, la réponse est oui.
je suis donc perdu, et j'ai vraiment besoin d'aide, je ne comprend absolument pas pourquoi client-serveur sur mon pc fonctionne parfaitement bien, et serveur sur un autre pc, limage est totalement inexploitable.

Pour la petite histoire:
je vis dans une famille nombreuse ou chacun m'apel sans cesse dés que son pc affiche une fenétre anormal, du genr le parfeu qui demande confirmation, IE qui demande d'étre lexplorer internet par defaut etc... c'est pourquoi codé une applicaton qui me permettrai davoir limprime ecran lorsque l'un ou l'autre veu me faire déplacer sans cesse pour rien ma semblait une excellente idée et projet.

Merci par avance
A voir également:

5 réponses

Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
30 juin 2009 à 10:22
Salut.
Et oui, dès fois on se sent seul... (comme toi mes questions trouvent rarement une réponse)
à mon avis, le plus propre c'est d'avoir une reception bloquante, c'est à dire que le read attend l'envoie de nouvelles données du serveur.
Tu peux aussi (peut être) utiliser la valeur retourner la la fonction de lecture.
D'un autre coté, il est très difficile de te répondre car nous n'avons pas tout ton code, et typiquement, il est impossible de trouver ton problème juste avec ce que tu donnes.
En particulier quelles fonction utilises tu pour lire écrire les socket, read ou recv ? quel config de socket etc. ?
1
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
30 juin 2009 à 12:49
Ok, tout s'explique.
Moi, dans ces cas là, je n'hésite pas à passer outre la classe qui me fait chier et à programmer "bas niveau".
J'ai un peu bidouiller les socket avec Qt (similaire à WxWidget je pense) et je pense que la bonne façon de faire c'est avec les signaux. Je sais que dès que le buffer est près qt:: socket envoie un signal, qu'il suffit alors de connecter avec une fonction qui va lire et mettre en file.
Une question se pose aussi. Es-tu sur que tes paquets arrivent dans l'ordre émis, il me semble qu'il n'y a pas de garanti en TCP IP. Alors il faut faire un accusé de réception à chaque paquet reçut et n'envoyer le suivant que lorsque l'accusé est reçu. Je ne pense pas que ce problème de séquence pose problème sur un réseau local assez peu encombré et de petite taille, mais à l'échelle d'Internet d'un continent à l'autre ?
1
djerem06 Messages postés 46 Date d'inscription jeudi 5 juin 2008 Statut Membre Dernière intervention 23 avril 2015 6
30 juin 2009 à 09:37
Bon alors personne ne s'est interraissé a mon probléme, ce n'est pas grave, c'est comme ça que j'ai toujour progressé, j'ai réussi a comprendre le pourquoi du comment, donc je donne la solution:

la boucle for de transmission du serveur fait deux choses:
-lire 512 octet dans le fichier
PUIS
-envoyer 512 octets par la socket

la boucle for de transmission du client fait deux chose aussi:
-lire 512 octet par le socket
PUIS
-inscrire cette lecture dans une variable

En l'ocurence, la lecture de 512 octet dans un fichier est une chose bien plus longue que copié 512 octet dans une variable (ROM - RAM)
de ce fait, et c'est une erreur trés béte, le client se remet a lire 512 octet avant que le serveur ne les ai deja emis ! La lecture d'octet n'est pas une opération bloquante, fort heureusement, mais dans mon cas:
for(i=0 ; i < ((taille/NbOctet) + 1) ; i++){
Client.Socket->Read(octet, NbOctet);
for(j = i*NbOctet ; j < (i*NbOctet + NbOctet) ;j++){
Client.contenu[j] = octet[j-i*NbOctet];
}
}
Le client recopi en boucle sa derniere reception de 512 octet dans la variable contenu jusqua se que la lenteur du serveur emette a nouveau.

Pour palier a ce probléme, deux solutions s'offre:

1er) soit on détermine que dans sa boucle for, le client lira un nombre tré inférieur a 512 afin de compenser le temps perdu par le serveur a lire le fichier, ou méme a attendre quelque miliseconde en chaque vague d'emission. (ça c'est une solution absolument vulguére :s dsl mais c juste grace a ça que j'ai aboutis a la seconde)

2nd) entre chaque vague d'emission d'octet, le client li en boucle 1 octet jusqua ce que cette octet lu soit un octet d'AK de la part du serveur, ayant fini de pomper les octet dans le fichier.
de ce fait, le client et le serveur se trouve parfaitement synchronisé, et le client ne lira aucun octet utile dans l'air.

Portion de code (transmission) CLIENT:
char ak=0x19;
unsigned long int ifor = ((taille/NbOctet) + 1);
for(i=0 ; i < ifor ; i++){
do{
Client.Socket->Read(&ak, 1);
}while(ak==0x19);
Client.Socket->Read(octet, NbOctet); //vague de reception
for(j = i*NbOctet ; j < (i*NbOctet + NbOctet) ;j++){
//Client.contenu est une chaine d'octet qui contiendra tou le fichier
Client.contenu[j] = octet[j-i*NbOctet];
}
}

Portion de code, SERVEUR:
char ak=0x91;//valeur totalement arbitraire pourvu quel soit différente de 0x19
for(i=0 ; i<((taille/NbOctet) + 1 ); i++){
re=read(idff, octet, NbOctet);
//lecture dans le fichier terminé, le serveur envoi l'AK, et directement les octet utile
Classe.ecrireOctets(&ak, 1);
re=Classe.ecrireOctets(octet, re);
}

bon bein voila, j'ai faibli a poser la question sur un forum, j'assume en y retournant la solution trouver par ma seul réfléxion.
byebye
0
djerem06 Messages postés 46 Date d'inscription jeudi 5 juin 2008 Statut Membre Dernière intervention 23 avril 2015 6
30 juin 2009 à 12:24
Salut et merci de t'interraissé a mon projet.
alors le souci c'est que le Client j'ai voulu le fair en wxWidget pour pouvoir bénéficier de sa simplicité de mise en euvre et surtout que le code peu étre compilé pour UNIX, et donc pour respecter ce wxWidget, j'ai du utiliser le Read et le Write de WxSocketBase (je crois) et ces méthode ne renvoyent pas le nombre d'octet effectivement lu ou ecri ! sa va de pair avec le fait qu'elle ne sont pas bloquante...

aprés pour le serveur (qui ne tournera que sur du Windob), j'ai utiliser les socket normal, jte fait un copier coller des lignes concerné:
-WSAStartup(MAKEWORD(2,0), &WSAData);
-socket (AF_INET, SOCK_STREAM, 0);
-idServeur.sin_family = AF_INET;
idServeur.sin_port = htons (PORT); //N° de port
idServeur.sin_addr.s_addr = htonl (INADDR_ANY); //Adresse IP
c'est vrai que j'ai laisser les méthode maison ecrirOctet et liceOctet, donc je me ser de:
recv et send
qui sont bien bloquant et renvoient le nombre d'octet effectivement lu ou ecrit, ce qui n'est pas le cas de Socket->Read et Socket->Write qui sont les deux méthode équivalente en wx (client)

c'est sur qu'avec un client et serveur équipé de méthode bloquante de lecture et ecriture d'octet sur le reseau, le problem ne se poserais pas, mais finalement je me suis dit qu'attendre le AK entre chaque volé, c'été un peu plus respectueux envers mon propre protocol d'échange :p
Bon donc du coup sa fonctionne a la perfection :)
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
djerem06 Messages postés 46 Date d'inscription jeudi 5 juin 2008 Statut Membre Dernière intervention 23 avril 2015 6
30 juin 2009 à 14:27
Excellente remarque ! j'ador!
effectivement je n'ai aucune garantis que les packet arrive dans l'ordre, il faudrais dédié les deux premier octet de chaque packet a contenir une valeur entiére incrémenté par le serveur entre chaque emission, et le client remettrais alors en ordre tout seul les packet a la fin de la transmission, ou comme tu dis, un AK entre chaque echange qui serais un transfére un poil plus long, mais plus simple a coder.
En revanche mon réseau famillial ne contient qu'un seul et unique neud entre 2 ordinateur, je ne risque donc pas la tempéte de broadcast (lol) et c'est pour sa que je ne me suis pas penché sur l'ordre des paquets (je me serais peu étre fait avoir :p)
en revanche j'ai souvent eu l'idé que tu réveille en moi: coder un client serveur qui s'entendent d'un continent a l'autre. mais ne divaguons pas sur ce topic :p
si tu es comme moi pationné de c++ et réseaux, ouvrons un topic privé sur ce sujet (?)
0