11
votes

Sun RPC: transfert de fichiers binaires

Je veux transférer des fichiers binaires sur un serveur distant. J'utilise Sun / Onc RPC (RPCGen sur Linux) pour mon code. J'utilise C. J'ai écrit du code pour serveur et client et cela fonctionne pour les fichiers texte, mais lorsque j'essaie de transférer des fichiers binaires, le fichier est corrompu après le transfert. Je stocke des morceaux de données dans le tableau de caractères ou les chaînes XDR. Je pense qu'il y a un problème avec moi avec moi stocker des données comme une matrice de caractères. Quelqu'un peut-il s'il vous plaît dites-moi quel est le problème? Quelqu'un peut-il m'aider s'il vous plaît?

J'attache mes extraits de code ici pour référence si quelqu'un veut regarder ce que je fais. p>

mon IDL: p>

#include <rpc/rpc.h>
#include <stdio.h>
#include <string.h>
#include "ftp.h"

extern __thread int errno;

int get_file(char *host, char *name)
{
    CLIENT *clnt;
    int total_bytes = 0, write_bytes;
    readfile_res *result;
    request req;
    FILE *file;

    req.name = name;
    req.start = 0;

    /*
     * Create client handle used for calling FTPPROG on
     * the server designated on the command line. Use
     * the tcp protocol when contacting the server.
     */
    clnt = clnt_create(host, FTPPROG, FTPVER, "tcp");
    if (clnt == NULL) {
        /*
         * Couldn't establish connection with server.
         * Print error message and stop.
         */
         clnt_pcreateerror(host);
         exit(1);
    }

    file = fopen(name, "wb");

    /*
     * Call the remote procedure readdir on the server
     */
    while (1) {
        req.start = total_bytes;
        result = retrieve_file_1(&req, clnt);
        if (result == NULL) {
            /*
             * An RPC error occurred while calling the server.
             * Print error message and stop.
             */
            clnt_perror(clnt, host);
            exit(1);
        }

        /*
         * Okay, we successfully called the remote procedure.
         */
        if (result->errno != 0) {
            /*
             * A remote system error occurred.
             * Print error message and stop.
             */
            errno = result->errno;
            perror(name);
            exit(1);
        }

        /*
         * Successfully got a chunk of the file.
         * Write into our local file.
         */
        write_bytes = fwrite(result->readfile_res_u.chunk.data, 1, result->readfile_res_u.chunk.bytes, file);
        total_bytes += result->readfile_res_u.chunk.bytes;
        if (result->readfile_res_u.chunk.bytes < MAXLEN) 
            break;
    }

    fclose(file);

    return 0;
}

int put_file(char *host, char *name)
{
    CLIENT *clnt;
    char data[1024];
    int total_bytes = 0, read_bytes;
    int *result;
    chunksend chunk;
    FILE *file;

    /*
     * Create client handle used for calling FTPPROG on
     * the server designated on the command line. Use
     * the tcp protocol when contacting the server.
     */
    clnt = clnt_create(host, FTPPROG, FTPVER, "tcp");
    if (clnt == NULL) {
        /*
         * Couldn't establish connection with server.
         * Print error message and stop.
         */
         clnt_pcreateerror(host);
         exit(1);
    }

    file = fopen(name, "r");

    chunk.name = name;

    /*
     * Call the remote procedure readdir on the server
     */
    while (1) {
        read_bytes = fread(data, 1, MAXLEN, file);
        total_bytes += read_bytes;

        chunk.data = data;
        chunk.bytes = read_bytes;
        result = send_file_1(&chunk, clnt);

        if (result == NULL) {
            /*
             * An RPC error occurred while calling the server.
             * Print error message and stop.
             */
            clnt_perror(clnt, host);
            exit(1);
        }

        /*
         * Okay, we successfully called the remote procedure.
         */
        if (*result != 0) {
            /*
             * A remote system error occurred.
             * Print error message and stop.
             */
            errno = *result;
            perror(name);
            exit(1);
        }

        /*
         * Successfully got a chunk of the file.
         * Write into our local file.
         */
        if (read_bytes < MAXLEN) 
            break;
    }

    fclose(file);

    return 0;
}

int read_command(char *host)
{
    char command[MAXLEN], filepath[MAXLEN];

    printf("> ");
    fflush(stdin);
    scanf("%s %s", command, filepath);

    if (strcmp(command, "get") == 0) {
        return get_file(host, filepath);
    } else if(strcmp(command, "put") == 0){
        return put_file(host, filepath);
    } else if(strcmp(command, "exit") == 0){
        exit(0);
    } else {
        return -1;
    }
}

int main(int argc, char *argv[])
{
   int result;

   if (argc != 2) {
        fprintf(stderr, "usage: %s host\n", argv[0]);
        exit(1);
   }

   while(TRUE) {
       result = read_command(argv[1]);
   }

   return 0;
}


0 commentaires

4 Réponses :


0
votes

Comparez les fichiers avant et après le transfert, cela vous dira où se trouve le problème. Vous pouvez utiliser hexdiff pour cela.


1 commentaires

Semble que seul un petit morceau du fichier vient lors de chaque itération de la boucle. Sur le côté serveur lorsqu'il lit le fichier, les tailles sont parfaites, mais lorsqu'elles sont reçues au client, elles sont toutes gâchées. Seule environ la moitié des données sont correctes!



4
votes

Les chaînes XDR sont NULL terminées. Vous devez utiliser un type de données différent pour transférer des données binaires - probablement 'Array d'octet'. Voir, par exemple, cette Document au soleil.


1 commentaires

Merci. J'avais eu ce travail avant que j'ai vu ce post. Quoi qu'il en soit, c'est la voie à suivre, j'utilise maintenant un tableau d'entiers!



4
votes

Un peu tard, je gess, mais voici une solution à votre problème: JUSTE Change le type de stockage d'un morceau du fichier à un réseau de longueur fixe de octets arbitraires. Donc, dans votre IDL, au lieu de la déclaration " Typedef String Filechunk ; strong>" Vous pouvez utiliser des données opaques: " Typedef opaque Filechunk [maxlen]; strong>" (matière de Fait, c'est juste un tableau fixe de char)

PS: ce type de données (réseaux fixes) vous empêche d'utiliser une variable comme tampon pour lire ou écrire à partir d'un fichier. Par exemple, dans la fonction * retrieve_file_1_svc * à partir de votre serveur, les instructions p> xxx pré>

doivent être modifiées en p>

*bytes = fread(res.readfile_res_u.chunk.data, 1, 1024, file);*


0 commentaires

2
votes

Juste pour référence future, madhusudan.ca possède une "solution" en utilisant des entiers vous donnera toutes sortes de plaisir lorsque vous utilisez des machines avec une endansion différente. RPC devrait traduire des entiers dans ce cas, en train de remédier à vos données de chaîne ou binaire.

La solution correcte utilise le type de données XDR 'opaque'. Il créera une structure avec un INT _len non signé pour la quantité d'octets et un pointeur _var que vous pouvez indiquer vos données.


0 commentaires