用了好几天的时间编写了一个ftp的客户端,使用socket通讯。服务器端使用的是vsftp,在centos下直接用yum install vsftpd安装即可。在这里我使用的是被动模式。
在编写代码时主要犯了错误:
1.在使用socket时,对于接受例如read,一定要使用其返回值,其返回值表示真正接收到的数据。而且,接受的长度为缓冲区的长度减一,其目的是为了保存'\0',在写入时,要写入接收到的字符串的长度len.
2.以下红色为自己出过错误的地方
3.要关闭服务器的防火墙服务

主要引用资料:http://www.ibm.com/developerworks/cn/linux/l-cn-socketftp/index.html

下边是代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define BUFFER_SIZE 1024
#define server_path "config/wang"    //the file you want to download

#define client_path "/opt/dcp/wang"    //要下载到本地的地址
#define username "wang"   //服务器的登陆名
#define code "1"           //服务器的登陆密码
#define server_ip "192.168.1.126" //vsftp 服务器的ip地址

int strseparte(const char *rmt_path,char *filename,char *rmt_dir)
{
    int i=0;
    const char *path=rmt_path;
    char *ptr1=strrchr(path,'/');
    if(ptr1==NULL)
    {
        while(*path!='\0')
        {
            filename[i]=*path;
            i++;
            path++;
        }
    }
    else
    {    
        while(path        {
            rmt_dir[i]=*path;
            i++;
            path++;
        }
        i=0;
        ptr1++;
        while(*ptr1!='\0')
        {
            filename[i]=*ptr1;
            i++;
            ptr1++;
        }
    }
    return 0;
}

int ftp_download(const char *ip,const char *rmt_path,const char *local_path)
{
    
    int socket_fd,date_fd;
    struct sockaddr_in server_sockaddr,date_sockaddr;
    
    char sendbuf[BUFFER_SIZE]={0};
    char recvbuf[BUFFER_SIZE]={0};
    
    int file;
    int len;
    int filesize;
    char filename[30]={0};
    char rmt_dir[50]={0};

    int porttmp1,porttmp2,port;
    int a1,a2,a3,a4,a5;
    char str1[30],str2[30],str3[30];
    
    if((socket_fd=socket(AF_INET,SOCK_STREAM,0))==-1)
    {
        perror("socket");
        exit(1);
    }

    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(21);
    server_sockaddr.sin_addr.s_addr = inet_addr(ip);
    if(connect(socket_fd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr)) != 0)
    {
        perror("connect");
        exit(1);
    }

    
    memset(recvbuf,0,sizeof(recvbuf));
    recv(socket_fd,recvbuf,sizeof(recvbuf),0);
//    printf("First recv message is:%s\n ",recvbuf);
    
    sprintf(sendbuf,"USER %s\r\n",username);
    write(socket_fd,sendbuf,strlen(sendbuf));
//    printf("First send message is:%s\n",sendbuf);
    read(socket_fd,recvbuf,sizeof(recvbuf));
//    printf("after write USER recv message is:%s",recvbuf);

    memset(sendbuf,0,sizeof(sendbuf));    
    sprintf(sendbuf,"PASS %s\r\n",code);
//    printf("second send message is:%s\n",sendbuf);
    write(socket_fd,sendbuf,strlen(sendbuf));

    memset(recvbuf,0,sizeof(recvbuf));
    read(socket_fd,recvbuf,sizeof(recvbuf));
//    printf("after write PASS recv message is:%s",recvbuf);

    
    memset(sendbuf,0,sizeof(sendbuf));
    sprintf(sendbuf,"PASV\r\n");
    write(socket_fd,sendbuf,strlen(sendbuf));
//    printf("pasv send is:%s\n",sendbuf);
    
    memset(recvbuf,0,sizeof(recvbuf));
    read(socket_fd,recvbuf,sizeof(recvbuf));
//    printf("after write PASV recv message is:%s",recvbuf);
    
    
    sscanf(recvbuf,"%d %s %s %s (%d,%d,%d,%d,%d,%d).",&a1,str1,str2,str3,&a2,&a3,&a4,&a5,&porttmp1,&porttmp2);        

//    printf("porttmp1=%d,porttmp2=%d\n",porttmp1,porttmp2);
    port=porttmp1*256+porttmp2;
    

    if((date_fd=socket(AF_INET,SOCK_STREAM,0))==-1)
    {
        perror("date_fd socket");
        exit(1);
    }
    date_sockaddr.sin_family = AF_INET;
    date_sockaddr.sin_port = htons(port);
    date_sockaddr.sin_addr.s_addr = inet_addr(ip);

    if(connect(date_fd, (struct sockaddr *)&date_sockaddr, sizeof(struct sockaddr)) != 0)
    {
        perror("date_fd connect");
        exit(1);
    }else
        printf("date_fd connect success\n");

    strseparte(rmt_path,filename,rmt_dir);
    
    if(rmt_dir!=NULL)
    {
        memset(sendbuf,0,sizeof(sendbuf));
        sprintf(sendbuf,"CWD %s\r\n",rmt_dir);
        write(socket_fd,sendbuf,strlen(sendbuf));
    //    printf("send cwd is:%s\n",sendbuf);

        memset(recvbuf,0,sizeof(recvbuf));
        read(socket_fd,recvbuf,sizeof(recvbuf));
    //    printf("after send cwd recv is:%s\n",recvbuf);
    }

    memset(sendbuf,0,sizeof(sendbuf));
    sprintf(sendbuf,"SIZE %s\r\n",filename);
    write(socket_fd,sendbuf,strlen(sendbuf));
//    printf("send SIZE is :%s\n",sendbuf);
    memset(recvbuf,0,sizeof(recvbuf));
    read(socket_fd,recvbuf,sizeof(recvbuf));
//    printf("after send file size recv is:%s\n",recvbuf);

    
    sscanf(recvbuf,"%d %d",&a1,&filesize);
//    printf("filesize is %d\n",filesize);
        
    memset(sendbuf,0,sizeof(sendbuf));
    sprintf(sendbuf,"RETR %s\r\n",filename);
    write(socket_fd,sendbuf,strlen(sendbuf));    

    memset(recvbuf,0,sizeof(recvbuf));
    read(socket_fd,recvbuf,sizeof(recvbuf));
//    printf("1 after retr recvbuf is:%s\n",recvbuf);

    memset(recvbuf,0,sizeof(recvbuf));
    file=open(local_path,O_RDWR|O_CREAT|O_TRUNC,0644);
    while(1)
    {
        if((len=read(date_fd,recvbuf,sizeof(recvbuf)-1))>0)
        {
            write(file,recvbuf,len);          
            printf("%s\n",recvbuf);
            memset(recvbuf,0,sizeof(recvbuf));
        }
        else
        {
            close(file);
            printf("download ok\n");
            break;
        }
    }

    close(date_fd);
    memset(recvbuf,0,sizeof(recvbuf));
    read(socket_fd,recvbuf,sizeof(recvbuf));
//    printf("download finish:%s\n",recvbuf);
    
    memset(sendbuf,0,sizeof(sendbuf));
    sprintf(sendbuf,"QUIT\r\n");
    write(socket_fd,sendbuf,strlen(sendbuf));

    memset(recvbuf,0,sizeof(recvbuf));
    read(socket_fd,recvbuf,sizeof(recvbuf));
//    printf("after send quit:%s\n",recvbuf);

    close(socket_fd);

}

int main(int argc,char *argv[])
{
        
    ftp_download(server_ip,server_path,client_path);
    
    return 0;
}
01-07 00:57