2010-01-17 30 views
9

Tôi muốn chuyển tệp nhị phân sang máy chủ từ xa. Tôi đang sử dụng SUN/ONC RPC (rpcgen trên Linux) cho mã của tôi. Tôi đang sử dụng C. Tôi đã viết mã cho máy chủ và khách hàng và nó hoạt động cho các tập tin văn bản, nhưng khi tôi cố gắng chuyển các tập tin nhị phân nó nói rằng tập tin bị hỏng sau khi chuyển giao. Tôi đang lưu trữ các khối dữ liệu trong chuỗi ký tự hoặc chuỗi XDR. Tôi nghĩ rằng có một số vấn đề với tôi lưu trữ dữ liệu như là một mảng ký tự. Có thể một số xin vui lòng cho tôi biết vấn đề là gì? Ai đó có thể vui lòng giúp tôi?RPC mặt trời: chuyển các tệp nhị phân

Tôi đang đính kèm các đoạn mã của tôi ở đây để tham khảo nếu một số người muốn xem những gì tôi đang làm.

IDL của tôi:

const MAXLEN = 1024; 

/* 
* Type for storing path 
*/ 
typedef string filename<MAXLEN>; 

/* 
* Structure for sending request. Expects the path of the file 
* and the byte number at which to start reading the file from 
*/ 
struct request { 
    filename name; 
    int start; 
}; 

/* 
* Type that represents the structute for request 
*/ 
typedef struct request request; 

/* 
* Type for storing a chunk of the file that is being 
* sent from the server to the client in the current 
* remote procedure call 
*/ 
typedef string filechunk<MAXLEN>; 

/* 
* Response sent by the server to the client as a response 
* to remote procedure call, containing the filechunk for 
* the current call and number of bytes actually read 
*/ 
struct chunkreceive { 
    filechunk data; 
    int bytes; 
}; 

/* 
* Type that represents the structure for file's chunks 
* to be received from the server 
*/ 
typedef struct chunkreceive chunkreceive; 

/* 
* File data sent by the server from client to store 
* it on the server along with the filename and the 
* number of bytes in the data 
*/ 
struct chunksend { 
    filename name; 
    filechunk data; 
    int bytes; 
}; 

/* 
* Type that represents the structure for file's chunks 
* to be sent to the server 
*/ 
typedef struct chunksend chunksend; 

/* 
* union for returning from remote procedure call, returns 
* the proper chunkdata response if everything worked fine 
* or will return the error number if an error occured 
*/ 
union readfile_res switch (int errno) { 
    case 0: 
     chunkreceive chunk; 
    default: 
     void; 
}; 

/* 
* Remote procedure defined in the Interface Definition Language 
* of SUN RPC, contains PROGRAM and VERSION name definitions and 
* the remote procedure signature 
*/ 
program FTPPROG { 
    version FTPVER { 
     readfile_res retrieve_file(request *) = 1; 
     int send_file(chunksend *) = 2; 
    } = 1; 
} = 0x20000011; 

máy chủ của tôi:

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

extern __thread int errno; 

readfile_res* retrieve_file_1_svc(request *req, struct svc_req *rqstp) 
{ 
    FILE *file; 
    char data[1024]; 
    int bytes; 
    static readfile_res res; 

    file = fopen(req->name, "rb"); 
    if (file == NULL) { 
     res.errno = errno; 
     return (&res); 
    } 

    fseek (file, req->start, SEEK_SET); 
    bytes = fread(data, 1, 1024, file); 

    res.readfile_res_u.chunk.data = data; 
    res.readfile_res_u.chunk.bytes = bytes; 

    /* 
    * Return the result 
    */ 
    res.errno = 0; 
    fclose(file); 
    return (&res); 
} 

int* send_file_1_svc(chunksend *rec, struct svc_req *rqstp) 
{ 
    FILE *file; 
    int write_bytes; 
    static int result; 

    file = fopen(rec->name, "a"); 
    if (file == NULL) { 
     result = errno; 
     return &result; 
    } 

    write_bytes = fwrite(rec->data, 1, rec->bytes, file); 
    fclose(file); 

    result = 0; 
    return &result; 
} 

Khách hàng của tôi:

#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; 
} 

Trả lời

4

Chuỗi XDR không được kết thúc. Bạn cần sử dụng một kiểu dữ liệu khác để chuyển dữ liệu nhị phân - có lẽ là 'mảng byte'. Xem, ví dụ: document này ở Mặt trời.

+0

Cảm ơn. Tôi đã làm việc này trước khi tôi thấy bài đăng này. Dù sao đó là con đường để đi, tôi bây giờ đang sử dụng mảng số nguyên! –

0

Hãy so sánh các tập tin trước và sau khi chuyển nhượng, sẽ cho bạn biết nơi mà vấn đề là . Bạn có thể sử dụng hexdiff cho điều đó.

+0

Dường như chỉ một đoạn nhỏ của tệp đang đến trong mỗi lần lặp của vòng lặp. Ở phía máy chủ khi nó đọc tệp, kích thước là hoàn hảo, nhưng khi nó được nhận ở phía máy khách, tất cả đều bị rối tung lên. Chỉ có khoảng một nửa số liệu là chính xác! –

3

một chút muộn tôi gess nhưng đây là một giải pháp cho vấn đề của bạn: Juste thay đổi loại để lưu trữ một đoạn tệp vào một dải độ dài cố định là byte tùy ý. Vì vậy, trong IDL của bạn, thay vì tuyên bố "chuỗi typedef filechunk <MAXLEN>;" của bạn có thể sử dụng dữ liệu Opaque: "typedef filechunk đục [MAXLEN];" (vấn đề của thực tế, nó chỉ là một mảng cố định của char)

PS: Loại dữ liệu đó (mảng cố định) ngăn bạn sử dụng biến làm bộ đệm để đọc hoặc ghi từ tệp. Ví dụ, trong hàm * retrieve_file_1_svc * từ máy chủ của bạn, những điều khoản

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

phải được thay đổi để

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

Chỉ cần để tham khảo trong tương lai, Madhusudan.CS sở hữu "giải pháp" sử dụng số nguyên sẽ cung cấp cho bạn tất cả các loại thú vị khi sử dụng máy móc với độ tin cậy khác nhau. RPC nên dịch số nguyên trong trường hợp đó, mucking lên chuỗi của bạn hoặc dữ liệu nhị phân.

Giải pháp đúng là sử dụng loại dữ liệu XDR 'đục'. Nó sẽ tạo một cấu trúc với một _len unsigned int cho số byte, và một con trỏ _var mà bạn có thể trỏ đến dữ liệu của bạn.

Các vấn đề liên quan