0

これは、サーバーが最初にファイル名を受け取り、次にファイルを送信するRETR コマンドの単純な実装です。

/************************* RECEIVE FILE NAME AND SEND FILE *************************/
if(recv(newsockd, buffer, sizeof(buffer), 0) < 0){
  perror("error receiving file name");
  onexit(newsockd, sockd, 0, 2);
}
other = strtok(buffer, " ");
filename = strtok(NULL, "\n");
if(strcmp(other, "RETR") == 0){
  printf("received RETR request\n");
} else onexit(newsockd, sockd, 0, 2);

fd = open(filename, O_RDONLY);
    if (fd < 0) {
    fprintf(stderr, "cannot open '%s': %s\n", filename, strerror(errno));
    onexit(newsockd, sockd, 0, 2);
}

if(fstat(fd, &fileStat) < 0){
    perror("Error fstat");
    onexit(newsockd, sockd, fd, 3);
}
fsize = fileStat.st_size;
if(send(newsockd, &fsize, sizeof(fsize), 0) < 0){
    perror("Error on sending file size\n");
    onexit(newsockd, sockd, fd, 3);
}

rc = sendfile(newsockd, fd, &offset, fileStat.st_size);
if(rc == -1) {
        fprintf(stderr, "error sending file: '%s'\n", strerror(errno));
        onexit(newsockd, sockd, fd, 3);
}
if((uint32_t)rc != fsize) {
    fprintf(stderr, "transfer incomplete: %d di %d bytes sent\n", rc, (int)fileStat.st_size);
    onexit(newsockd, sockd, fd, 3);
}
memset(buffer, 0, sizeof(buffer));
strcpy(buffer, "226 File trasferito con successo\n\0");
if(send(newsockd, buffer, strlen(buffer)+1, 0) < 0){
  perror("Errore durante l'invio 226");
  onexit(newsockd, sockd, 0, 2);
}
memset(buffer, 0, sizeof(buffer));
strcpy(buffer, "221 Goodbye\n\0");
if(send(newsockd, buffer, strlen(buffer)+1, 0) < 0){
  perror("Errore durante l'invio 221");
  onexit(newsockd, sockd, 0, 2);
}
/************************* END PART *************************/

これはクライアント プログラムのスニペットです。

/************************* SEND FILE NAME AND RECEIVE FILE *************************/
printf("Inserire il nome del file da scaricare: ");
if(fgets(dirpath, BUFFGETS, stdin) == NULL){
    perror("fgets name file");
    close(sockd);
}
filename = strtok(dirpath, "\n");
sprintf(buffer, "RETR %s", dirpath);
if(send(sockd, buffer, strlen(buffer), 0) < 0){
    perror("error sending file name");
    close(sockd);
    exit(1);
}
if(read(sockd, &fsize, sizeof(fsize)) < 0){
    perror("error on receiving file size\n");
    close(sockd);
    exit(1);
}
fd = open(filename, O_CREAT | O_WRONLY, 0644);
if (fd  < 0) {
    perror("open");
    exit(1);
}

while(((uint32_t)total_bytes_read != fsize) && ((nread = read(sockd, filebuffer, fsize)) > 0)){
    if(write(fd, filebuffer, nread) < 0){
        perror("write");
        close(sockd);
        exit(1);
    }
    total_bytes_read += nread;
}
memset(buffer, 0, sizeof(buffer));
if(recv(sockd, buffer, 34, 0) < 0){
    perror("Error receiving 226");
    close(sockd);
    exit(1);
}
printf("%s", buffer);
memset(buffer, 0, sizeof(buffer));
if(recv(sockd, buffer, 13, 0) < 0){
    perror("Error receiving 221");
    close(sockd);
    exit(1);
}
printf("%s", buffer);
memset(buffer, 0, sizeof(buffer));
close(fd);
/************************* END PART *************************/

何が問題ですか?問題は、送信されたファイルにサーバーから送信された 2 つのメッセージ ( 226と 221) も含まれていること です
。なぜこのような動作になったのかわかりません。con successo 221 さようなら」

RETR tryfile.txt
File tryfile.txt received
cat tryfile.txt



4

2 に答える 2

1

strlen() は\0 をカウントしないため、strlen() は 12 を返します。

strcpy(buffer, "221 Goodbye\n\0");
if(send(newsockd, buffer, strlen(buffer), 0) < 0){ ...}

クライアントは、ハードコードされた値 13 を使用します (33 が送信され、34 が予期される他のステータス メッセージについても同じです) 。

更新:「埋め込まれたヌル」を含む文字列の strlen を表示するには:

#include <stdio.h>
#include <string.h>

int main(void)
{
fprintf(stderr, "strlen is %u\n", (unsigned) strlen("221 Goodbye\n\0") );

return 0;
}

説明: strlen()は、'\0' 文字に遭遇するまで、単に文字をカウントします。

于 2012-07-08T17:11:58.507 に答える
0

私は問題を見つけて(最終的に)解決しました。
解決策は次のとおりです。

uint32_t fsize_tmp = fsize;
while(((uint32_t)total_bytes_read != fsize) && ((nread = read(sockd, filebuffer, fsize_tmp)) > 0)){
     if(write(fd, filebuffer, nread) < 0){
    perror("write");
    close(sockd);
    exit(1);
      }
      total_bytes_read += nread;
      fsize_tmp -= nread;
}

問題は、「動的」ファイルサイズをチェックしていなかったという事実によるものでした(ファイルが75%で送信された場合、whileループは再びfsizeを期待し、これは不可能でした)。したがって、このコードでは毎回ファイルサイズを減らします必要です:)

于 2012-07-08T15:40:04.690 に答える