使用 C 中的套接字将文件发送到 ftp 服务器

Send file to ftp server using sockets in C

我正在尝试使用套接字将文件上传到我的 ftp 服务器。它连接到服务器并可以读取目录但不上传文件。 "STOR" 命令在服务器中创建一个内容为空的文件。为什么我从服务器收到 "No data connection" 响应而我的文件是空的?

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    argv[0]="2";
    argv[1]="ip";

    int sockfd = 0, n = 0;
    char recvBuff[1024];
    struct sockaddr_in serv_addr;
    char mesUser[100]="USER ftpuser\n";
    char mesPass[100]="PASS pass\n";
    char meStor[100]="STOR xx\n";
    char mesPasv[100]="PASV\n";
    char meAppe[100]="APPE xx\n";

    argc=2;

    if(argc != 2)
    {
        printf("\n Usage: %s <ip of server> \n",argv[0]);
        return 1;
    }

    memset(recvBuff, '0',sizeof(recvBuff));
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Error : Could not create socket \n");
        return 1;
    }

    memset(&serv_addr, '0', sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(21);

    if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
     {
     printf("\n inet_pton error occured\n");
     return 1;
     }


    //serv_addr.sin_addr.s_addr = inet_addr(argv[1]);

    if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("\n Error : Connect Failed \n");
        return 1;
    }

    if( send(sockfd , mesUser , strlen(mesUser) , 0) < 0)
    {
        perror("send failed");
        return 1;
    }

    if( send(sockfd , mesPass , strlen(mesPass) , 0) < 0)
    {
        perror("send failed");
        return 1;
    }

    char* fr_name = "pic.jpg";
    FILE *fr = fopen(fr_name, "r");
    if(fr == NULL){
        printf("File cannot be opened");
        return 0;
    }
    else{

        /*if( send(sockfd , mesPasv , strlen(mesPasv) , 0) < 0)
        {
            perror("send failed");
            return 1;
        }*/

        if( send(sockfd , meStor , strlen(meStor) , 0) < 0)
        {
            perror("send failed");
            return 1;
        }



        char buffer[100];
        fscanf(fr,"%s",buffer);
        write(sockfd,buffer,100);


        if( send(sockfd , meAppe , strlen(meAppe) , 0) < 0)
        {
            perror("send failed");
            return 1;
        }
        //close(sockfd);


    }

    /*if( send(sockfd , meStor , strlen(meStor) , 0) < 0)
    {
        perror("send failed");
        return 1;
    }
    */

    while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
    {
        recvBuff[n] = 0;
        if(fputs(recvBuff, stdout) == EOF)
        {
            printf("\n Error : Fputs error\n");
            return 0;
        }
    }

    if(n < 0)
    {
        printf("\n Read error \n");
        return 0;
    } 

    return 0;
}

输出:

 220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 6 of 50 allowed.
220-Local time is now 14:41. Server port: 21.
220 You will be disconnected after 15 minutes of inactivity.
331 User username OK. Password required
230 OK. Current restricted directory is /
425 No data connection
425 No data connection

看来您对FTP协议的理解还不全面。 FTP 致力于在客户端和服务器之间建立 2 个套接字连接的想法。第一个是 "control" 连接,第二个是 "data" 连接。在控制连接上,文本命令来回发送,就像您在代码中所做的那样。当需要来回发送数据时,使用数据连接完成。

FTP有两种方式建立数据连接,described here:

  • 活动:客户端指定一个端口到服务器,服务器连接到客户端机器上的那个端口。这很糟糕,因为防火墙和 NAT 的设计正是为了避免这类连接。
  • 被动:服务器给客户端一个连接端口,客户端连接到服务器机器上的那个端口。

简而言之,您需要:

  1. 使用PASV命令。
  2. 解析服务器的响应以获取端口号(可能使用scanf)。
  3. 打开到服务器上该端口的数据连接。
  4. 通过该数据连接放置您的文件。

自从我上次用 C 编写套接字以来已经有一段时间了,我没有时间编写示例,但这应该足以让您入门。 (Here 是 FTP 的规范。像这样的 RFC 读起来很费力,但它们是明确的,可以回答很多问题,如果你能学会阅读它们的话。)

我希望这对你有用:

int receiveFile(int socket, char text[]) {
FILE *fp;
int nsize,k, i, size=0, temp_size, mul = 1, numbytes, lala, recvd; 
int count_freq, repeat;
char ch,buf[20],file_buf[505], temp_buf[505];
saferead(socket, text,80);
if(text[0] == '/')  
    return 1;


nsize = strlen(text);
char name[nsize];
strncpy(name, text, nsize-1);
name[nsize-1] = '[=10=]';   

if ((fp = fopen(name,"w")) == NULL) {
        perror(" Can't open file");
    return 1;
}

if ((numbytes=recv(socket, buf, 10, 0)) == -1) {
    perror("Cant receive size of the file....\n\n");
    return 1;
}

for( i=0; i<=9; i++ ){
    size =  size + ( buf[i]*mul );
    mul = mul * 10;
}


recvd = 0;
printf("Received File: %s\n", name);
repeat = size/MAXDATASIZE;

if ( repeat>50 )
    count_freq = repeat/50;

i=0;    
while( recvd < size ){

    if ((numbytes=recv(socket, temp_buf, MAXDATASIZE, 0)) == -1) {
        perror("Error receiving file from server....\n\n");
        return 1;
    }

    fwrite( temp_buf, sizeof(temp_buf[0]), numbytes, fp );
    recvd = recvd + numbytes;
}
fclose(fp);  

}

int sendFile(int socket, char text[]) {
FILE *fp;
int size =0, k, status, nsize = 0, temp_size, i, sent, numbytes, lala;
char buf[20], file_buf[505], temp_buf[505];
char ch;
struct stat info;

nsize = strlen(text);
char name[nsize];
lala = strlen(name);
strncpy(name, text, nsize-1);
name[nsize-1] = '[=11=]';   
lala = strlen(name);

if((fp = fopen(name, "r")) == NULL) {
    perror("Can't open file");
    text[0] = '/';
    write(socket,text, 80);
    return 1;
}
write(socket,text, 80);    
printf("Sending File: %s\n",text);

status = stat( name,&info );

if( status == -1 ){
    printf(" fstat failed \n");
    return 1;
}
size = info.st_size;
temp_size = size;

for( i=0; i<=9; i++ )   {
    buf[i] =  size%10;
    size = size/10;
}

if (send(socket, buf, 10, 0) == -1){
    perror("Cant send file size...\n\n");
    return 1;
}


i = 0;
sent = 0;
while( sent <= temp_size ){
    ch = fgetc(fp);
    if( sent == temp_size ){
        if (i>0){
            if (( numbytes = send(socket, file_buf, i, 0)) == -1)
                perror("Error in sending file.....\n\n\n");
        }
            break;
    }

    file_buf[i++] = ch;

    if(i == MAX_BUFSIZE){                   
        if (( numbytes = send(socket, file_buf, MAX_BUFSIZE, 0)) == -1)
                perror("Error in sending file....\n\n\n");
            i = 0;
    }   
        sent++;
}

fclose(fp);

}