8
votes

Envoi d'images sur les sockets C ++ (Linux)

J'essaie d'envoyer des fichiers sur des sockets. J'ai créé un programme qui fonctionne pour des types de fichiers tels que .cpp , .txt et d'autres fichiers texte. Mais fichiers binaires, images ( .jpg et .png ) et fichiers compressés tels que .zip et .rar ne sont pas envoyés correctement. Je sais que cela n'a rien à voir avec la taille des fichiers car j'ai testé avec des fichiers de gros .txt . Je ne vois pas le problème. Je reçois tous les octets envoyés, mais le fichier ne peut pas être ouvert. La plupart du temps, le fichier est corrompu et ne peut pas être consulté. J'ai cherché à Google pour une réponse et j'ai trouvé d'autres personnes avec le même problème mais aucune solution. Donc, en m'aidant, vous aidez également quelqu'un d'autre à avoir besoin d'une solution.

  • Code serveur xxx
    • Code client xxx

5 commentaires

Est-ce vraiment spécifique Linux?


@Lorenzo - Si vous ne savez pas quel est le problème, comment savoir à l'avance? Vous pouvez simplement demander raisonnablement s'il est associé C ++. Où dessinons-nous la ligne?


Cependant, je ne trouve aucune bonne raison de dire qu'il s'agit d'un problème spécifique de Linux. Il est probablement présent sur chaque système fournissant une interface de prise.


@Lorenzo - oui mais vous savez que déjà. Le saviez-vous lorsque vous écriviez votre 10ème programme C et commencié à expérimenter avec des prises?


Ce n'est pas c ++ spécifié non plus; Je suggérerais de supprimer les balises Linux et C ++ et de les remplacer à la fois avec des "prises" seulement.


5 Réponses :


0
votes

Pour lire des fichiers texte ASCII, un tampon char est acceptable.

Pour lire des données binaires, vous devrez utiliser non signé Char , sinon vos données vont être remplies, car les données binaires sont non signées d'octets.


4 commentaires

Maintenant, j'ai un problème d'essayer de comparer le tampon de charme non signé avec "hi" pour voir si je devrais terminer le transfert (côté serveur)


Ce qui signifie que ce n'est probablement pas le meilleur moyen de signaler la fin de votre transfert de données. Question à réfléchir à: Que se passe-t-il si les données que vous envoyez ont réellement "HI" à la fin?


Dans ce cas, il n'y aura pas de signe de signe par fwrite (), de sorte que CHAR fonctionnera bien, même s'il y a des données de 8 bits dans le fichier.


Les données sont des données et tant que vous ne faites aucune opération avec elle, peu importe si elle est non signée ou non (sauvegarde pour la vérification de type).



4
votes

Premièrement, vous devriez essayer d'augmenter votre tampon à quelque chose de plus grand. Plus le tampon est grand, plus le transport est efficace (n'exagérez tout simplement pas et consommez trop de mémoire locale).

Deuxièmement, vous devriez vérifier et utiliser les longueurs renvoyées par les fonctions de lecture et d'écriture. Dans toutes vos lectures et vous écrit seulement, vérifiez si quelque chose était lu / écrit, mais vous devez utiliser ce numéro d'octet sur votre prochaine opération d'écriture / lecture. Par exemple, si le client indique qu'il a lu 1 octet, vous ne devez écrire que 1 octet sur le disque. De plus, si vous avez 1024 octets lus à partir du serveur, vous devez essayer d'écrire 1024 octets sur le disque, ce qui pourrait ne pas arriver dans cet appel et vous aurez peut-être besoin d'un autre appel à l'écriture pour terminer l'opération.

Je sais que cela ressemble à beaucoup de travail, mais c'est comme ça que cela doit être fait pour garantir des opérations d'E / S. Toutes les lis et écrire ont essentiellement à faire à l'intérieur de leurs propres boucles.


0 commentaires

2
votes

Savez-vous que votre fichier image binaire n'a pas de séquence d'octets 0x48 0x69 ( "hi" ) dessus? Votre boucle de lecture sera terminée dès qu'il reçoit cette séquence. De plus, vous appelez strcmp () avec un tampon de caractères à deux octets longs et garantit presque certainement qu'il n'a pas d'octet de terminaison null ( '\ 0' ).

Vous pouvez également enquêter sur la manière dont les fichiers diffèrent? L'outil CMP peut vous donner une liste d'octets différents entre la source et la destination.

Pour l'exactitude, vous voulez définitivement vérifier les résultats de retour de lisez () , écrire () , envoyer () , et ainsi de suite . La possibilité de lectures courtes et écrites avec des sockets est très élevée, il est donc d'une importance vitale que votre code soit capable de gérer les cas où toutes les données ne sont pas transférées. Depuis que vous ne suivez pas combien d'octets sont retournés par RECV () , il est possible que vous ne receviez qu'un octet unique, mais a écrit deux octets dans le écrire () appel à la suite.

Pour les performances, un tampon plus grand contribuera à réduire les frais généraux du système des appels à déplacer les données autour, bien qu'il soit acceptable de faire des opérations plus petites si la bande passante et la latence ne sont pas des préoccupations primordiales. Et ils ne devraient pas être jusqu'à ce que vous ayez un comportement correct.

Enfin, pour la compatibilité avec des systèmes d'exploitation moins éclairés, vous devez ouvrir les fichiers en mode binaire avec "rb" et "wb" de sorte que les nouvelles lignes ne sont pas gérées pendant la écrire.


0 commentaires

0
votes

Le problème est que vous ouvrez les fichiers dans texte avec fopen (..., "r") et fopen (... , "w") . Vous devez utiliser le mode binaire ( "rb" et "wb" ) pour les fichiers non-texte.


2 commentaires

Bien qu'il soit important de la compatibilité avec Windows et Ancien Mac OS, cela n'a pas d'importance sur les plates-formes dérivées UNIX telles que OS X ou Linux (comme l'a dit l'affiche qu'il utilisait).


Quelle est la différence entre "RB" et "WB"?



0
votes

Autres ont souligné vos problèmes avec votre code, à savoir:

  • n'utilisez pas les valeurs de retour de Lecture (2) et écrire (2) appels,
  • mélange de données binaires et de données de contrôle de caractère,
  • en utilisant STRCMP (3) sur les chaînes qui pourraient ne pas être terminées zéro (permettez-moi de noter que l'utilisation de fonctions s'appuyant sur la terminaison de zéro sur les données reçues du réseau n'est généralement pas une bonne idée, et souvent conduit à des dépassements de tampon.)

    Vous seriez bien mieux de définir un protocole simple pour le transfert de fichier (lisez le " La page Ultimate SO_LINGER, ou: pourquoi mon TCP n'est pas fiable " si vous voulez savoir pourquoi. Laisser le serveur Capacité saisonnée avant la quantité de données que vous envoyez - précède le transfert avec un en-tête de taille fixe contenant la longueur du fichier (pouvant également inclure le nom de fichier, mais vous devez également faire appel à la longueur de ce nom.) Faites attention à Numéro Endianness - toujours envoyer des numéros dans Commande d'octets de réseau .

    Depuis que vous êtes sur Linux, permettez-moi également de vous diriger vers sendfile (2) , qui est un moyen très efficace d'envoyer des fichiers, car il évite de copier des données à / en provenance d'Userland.


0 commentaires