c envoyer et recevoir des fichiers
C'est le serveur (sendfile) de la partie:
offset = 0;
for (size_to_send = fsize; size_to_send > 0; ){
rc = sendfile(newsockd, fd, &offset, size_to_send);
if (rc <= 0){
perror("sendfile");
onexit(newsockd, sockd, fd, 3);
}
offset += rc;
size_to_send -= rc;
}
close(fd); /* la chiusura del file va qui altrimenti rischio loop infinito e scrittura all'interno del file */
memset(buffer, 0, sizeof(buffer));
strcpy(buffer, "226 File Successfully transfered\n");
if(send(newsockd, buffer, strlen(buffer), 0) < 0){
perror("Errore durante l'invio 226");
onexit(newsockd, sockd, 0, 2);
}
memset(buffer, 0, sizeof(buffer));
et c'est la part du client (recv fichier) de la partie:
fsize_tmp = fsize;
sInfo.filebuffer = malloc(fsize);
if(sInfo.filebuffer == NULL){
perror("malloc");
onexit(sockd, 0, fd, 4);
}
while(((uint32_t)total_bytes_read != fsize) && ((nread = read(sockd, sInfo.filebuffer, fsize_tmp)) > 0)){
if(write(fd, sInfo.filebuffer, nread) != nread){
perror("write RETR");
onexit(sockd, 0, 0, 1);
}
total_bytes_read += nread;
fsize_tmp -= nread;
}
close(fd); /* la chiusura del file va qui altrimenti client entra in loop infinito e si scrive all'interno del file */
memset(buffer, 0, sizeof(buffer));
if(recv(sockd, buffer, 34, 0) < 0){
perror("Errore ricezione 226");
onexit(sockd, 0, 0, 1);
}
printf("%s", buffer);
memset(buffer, 0, sizeof(buffer));
memset(dirpath, 0, sizeof(dirpath));
free(sInfo.filebuffer);
Le problème, c'est que la chaîne "226 Fichier etc etc" est écrit à l'intérieur de le fichier qui a été envoyé.
J'ai essayé de faire un petit debug et j'ai donc ajouté un printf
après la boucle for (serveur de sendfile) et un printf
après la boucle while (client) et j'ai remarqué que le fichier est envoyé, mais sur le client, il n'est pas sortie du tout, car le printf
n'est pas imprimé...
Pourquoi j'ai eu ce comportement étrange??
br>
EDIT:
Le serveur renvoie la taille du fichier pour le client avec ce code:
fd = open(filename, O_RDONLY);
if(fd < 0){
error!!
}
if(fstat(fd, &fileStat) < 0){
perror("Errore fstat");
onexit(newsockd, sockd, fd, 3);
}
fsize = fileStat.st_size;
if(send(newsockd, &fsize, sizeof(fsize), 0) < 0){
perror("Errore durante l'invio della grandezza del file\n");
onexit(newsockd, sockd, fd, 3);
}
le client reçoit le fsize à partir du serveur avec ce code:
if(read(sockd, &fsize, sizeof(fsize)) < 0){
perror("Errore durante ricezione grandezza file\n");
onexit(sockd, 0 ,0 ,1);
}
fd = open(sInfo.filename, O_CREAT | O_WRONLY, 0644);
if (fd < 0) {
perror("open");
onexit(sockd, 0 ,0 ,1);
}
fsize_tmp = fsize;
les deux fsize
sont déclarées comme uint32_t
...
OriginalL'auteur polslinux | 2012-08-14
Vous devez vous connecter pour publier un commentaire.
Essayez ce code:
Côté Client:
Côté serveur:
MODIFIER : Ajout d'explication de la part de l'homme sur la
offset
La page de man d'envoyer le fichier a dit:
Bienvenue :-. ok grande.il y avait aussi un problème au sujet de incrémenter le décalage sur le côté serveur.
vraiment?? pourquoi?? Pouvez-vous m'expliquer svp??? Merci 🙂
Oui, dans votre code vous incrémenter la valeur de décalage (offset += rc;), il n'est pas nécessaire pour cela (dans mon code "côté Serveur" je vous donne deux fprintf pour voir ce qui va le décalage lors de l'envoi de données)
J'ai tester le code pour envoyer un simple fichier texte avec bonjour. Toutefois, le fichier que j'ai reçu sur le client, la taille est toujours vide. Après avoir fait référence à ce post tldp.org/LDP/LGNET/91/misc/tranter/server.c.txt et de lire l'avertissement, je trouve l'avertissement qui dit décalage variable ne doit pas être de type int, alors j'ai changer de type de décalage de int à off_t, et la sendfile fonctionne très bien.
OriginalL'auteur TOC
Le client ne sait pas quand le fichier se termine. Simplement, il lit jusqu'à ce qu'il a reçu
fsize
octets.Dans votre implementaton le client ne fonctionne que pour les fichiers qui sont exactement
fsize
octets.Je vous suggère de changer votre protocole et ajouter un en-tête qui contient la taille du fichier.
Pourquoi ne pas utiliser le protocole http?
J'ai lu votre mise à jour. Semble que la seule chose qui manque est le
send
de commande pour la taille du fichier.vous avez raison! j'ai mis à jour ma question! j'ai aussi trouvé le problème: le serveur envoie le droit fsize mais le client de recevoir un très grand fsize 🙁 🙁 par exemple si fsize est 1048 sur le serveur, le client reçoit 20209320 O. o
Serveur Linux et le client est Windows? Utilisation
htonl
sur le côté envoi de convertir la taille du réseau d'ordre des octets. Utilisationntohl
sur le côté de réception pour le convertir à partir du réseau à l'ordre des octets de l'hôte.le client et le serveur sont sur Ubuntu 12.04!
OriginalL'auteur Klas Lindbäck
Je pense que vous devriez obtenir une image plus détaillée de code avec au moins les variables utilisées déclarations et d'initialisation.
Comment fonctionne la partie client d'obtenir la fsize valeur ?
Vous devriez également vérifier la condition du while comme ceci :
N'utilisez pas "!=", parce que si (pour une raison inconnue) total_bytes_read devenir plus grand que fsize, vous serez coincé dans une boucle infinie jusqu'à ce que la connexion de socket est fermé (et renvoie une erreur).
Je pense aussi (mais pas sûr) que vous devez utiliser recv au lieu de lire dans votre partie client.
recv(2)
etread(2)
dans ce cas.fstat(fd, &fileStat); fsize = fileStat.st_size;
pour obtenir de plus simple exemple, je ne suis pas vérifiant l'erreurOriginalL'auteur phsym
Vous devez toujours déterminer la taille de fichier que vous envoyez dans le cadre du protocole, par exemple, vous pouvez envoyer la taille de fichier que les 4 premiers (ou plus, selon les tailles de fichier que vous attendez de la poignée) octets, avant que le flux réel.
Si vous souhaitez travailler avec la constante de la taille des fichiers, votre application devrait fonctionner, dans ce cas, veuillez ajouter imprime pour fsize et total_bytes_read.
OriginalL'auteur Ishay Peled
Vous utilisez le
sendfile
API de manière incorrecte. Puisque vous êtes de passage dans une valeur non NULLE dans le troisième paramètre,sendfile
permettra de mettre à jour le décalage pour vous. Mais parce que votre envoyer boucle est également mise à jour le décalage, vous serez en sautant sur quelques octets dans le cas quesendfile
n'a pas été en mesure d'envoyer l'ensemble du dossier en un seul appel.De la page de man:
Vous devriez supprimer cette ligne à partir de votre envoyer boucle:
Edit:
Dans votre mise à jour, vous utilisez(Ceci a été corrigé dans encore une autre mise à jour.) En tout cas, j'ai écrit un programme de test à l'aide du code que vous avez fourni (avec ma suggestion de correction), et il semble bien fonctionner avec un peu moins de 2 KO fichier et un fichier de 3 mo.fpl
pour obtenir lefstat
informations à partir de votre fichier, mais dans votresendfile
code, vous utilisezfd
. Je voudrais vous assurer que ces sont ce à quoi vous vous attendez à les trouver.aussi, je pense que l'utilisation d'un var est correct parce que
man sendfile
rapport: Si le décalage n'est pas NULL, alors il pointe vers une variable contenant le fichier offset à partir de laquelle sendfile() démarre la lecture des données à partir de in_fd.J'ai mis à jour la réponse avec l'intégralité de la citation de la page de man.
Aussi, comme d'autres l'ont vous a demandé de le faire, veuillez fournir une indication de la façon dont vous assurez-vous que le
fsize
valeur est la même pour l'émetteur et le récepteur.j'ai mis à jour ma question!
OriginalL'auteur jxh