基于socket的ftp实现(一)

服务器端的实现:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>//sockaddr_in等结构的定义
#include <netdb.h>//addrinfo等结构的定义
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#define TRUE 1
#define LISTEN_PORT 3499
#define dataLen 1024

char currentDirPath[200];
char currentDirName[30];
char help[]="get    get a file from server\n\
put    upload a file to server\n\
pwd    display    the current directory of server\n\
dir    display the files in the current directory of server\n\
cd    change the directory of server\n\
?    display the whole command which equals 'help'\n\
quit    return\n";

char *getDirName(char *dirPathName);
void cmd_pwd(int sock);
void cmd_dir(int sock);
void cmd_cd(int sock,char *dirName);
void cmd_cdback(int sock);
void cmd_help(int sock);
void cmd_get(int sock,char*fileName);
void cmd_put(int sock,char *fileName);
 
int main(int argc,char *argv[])
{
   int sock,sockmsg, length, lengthmsg;
   char client_cmd[10] , cmd_arg[20];
   struct sockaddr_in server;
   struct sockaddr_in servermsg;
   int datasock, msgsock;     
   pid_t child;
 
  // int datasock;   //data socket
   int rval;
   sock=socket(AF_INET,SOCK_STREAM,0);//创建流式套接字
   sockmsg=socket(AF_INET,SOCK_STREAM,0);
   if (sock<0||sockmsg<0)
   {
     perror("opening stream socket");
     exit(1);
   }
 
   server.sin_family=AF_INET;//AF_INET针对internet,另一种形式AF_UNIX只能够用于单一的Unix系统进程通信(主机通信协议)
   server.sin_addr.s_addr=INADDR_ANY;//表示可以和任何主机通信
   server.sin_port=htons(LISTEN_PORT);//htons将短整形数据转换位网络字节顺序

 
   servermsg.sin_family=AF_INET;
   servermsg.sin_addr.s_addr=INADDR_ANY;
   servermsg.sin_port=htons(LISTEN_PORT+1);

   if (bind(sock,(struct sockaddr *)&server,sizeof server)<0||bind(sockmsg,(struct sockaddr *)&servermsg,sizeof servermsg)<0)//将本地端口与socket返回的文件描述符绑定在一起
   {
     perror("binding stream socket");
     exit(1);
   }
   
   length=sizeof server;
   lengthmsg=sizeof servermsg;
   if (getsockname(sock,(struct sockaddr *)&server,&length)<0||getsockname(sockmsg,(struct sockaddr *)&servermsg,&lengthmsg)<0)//用于得套接口的名字
   {
     perror("getting socket name");
     exit(1);
   }
 
   printf("Socket port # %d  %d\n",ntohs(server.sin_port),ntohs(servermsg.sin_port));

   memset(currentDirPath,0,sizeof(currentDirPath));//将currentDirpath置零
   getcwd(currentDirPath,sizeof(currentDirPath));//得到当前路径,保存在currentDirPath中
 
   listen(sock,2); //监听,允许最大监听数位2,将绑定的套接字变成监听套接字
   listen(sockmsg,2);
   do  
   {
      datasock = accept(sock,(struct sockaddr*)0,(int*)0);//接受请求
      msgsock = accept(sockmsg,(struct sockaddr*)0,(int*)0);
      if (datasock == -1||msgsock==-1)
        perror("accept");
      else
      {
        if((child=fork())==-1)//创建子进程
        {
            printf("Fork Error!\n");
        }
        //The child process
        if(child==0)
        {
            printf("connection accepted! new client comming\n");
loop:
            memset(client_cmd,0,sizeof(client_cmd));
            rval=0;
            rval=read(msgsock,client_cmd,sizeof(client_cmd));//从msgsock中读取数据到client_cmd
 
            if(rval<0)
            {
                perror("reading command failed\n");
            }
            else if(rval==0)
            {
                printf("connection closed.\n");
                close(datasock);//关闭套接字
                close(msgsock);
            }
            else
            {
                if(strcmp(client_cmd,"pwd")==0)
                {
                    printf("cmmand pwd\n");
                    cmd_pwd(datasock);
                    printf("done\n\n");
                    goto loop;
                }
                else if(strcmp(client_cmd,"dir")==0)
                {
                    printf("command dir\n");
                    cmd_dir(datasock);
                    printf("done\n\n");
                    goto loop;
                }
                else if(strcmp(client_cmd,"cd")==0)
                {
                    printf("command cd\n");
                    //read the argument
                    memset(cmd_arg,0,sizeof(cmd_arg));
                    read(msgsock,cmd_arg,sizeof(cmd_arg));
                    cmd_cd(datasock,cmd_arg);
                    printf("done\n\n");
                    goto loop;
                }
                else if(strcmp(client_cmd,"cd..")==0)
                {
                    printf("command cd..\n");
                    cmd_cdback(datasock);
                    printf("done\n\n");
                    goto loop;
                }
                else if(strcmp(client_cmd,"get")==0)
                {
                    printf("command get\n");
 
                    memset(cmd_arg,0,sizeof(cmd_arg));
                    read(msgsock,cmd_arg,sizeof(cmd_arg));
                    cmd_get(datasock,cmd_arg);
                    printf("done\n\n");
                    goto loop;
                }
                else if(strcmp(client_cmd,"put")==0)
                {
                    printf("command put\n");
 
                    memset(cmd_arg,0,sizeof(cmd_arg));
                    read(msgsock,cmd_arg,sizeof(cmd_arg));
                    cmd_put(datasock,cmd_arg);
                    printf("done\n\n");
                    goto loop;
                }
                else if(strcmp(client_cmd,"?")==0)
                {
                    printf("command ?\n");

                    cmd_help(datasock);
                    printf("done\n\n");
                    goto loop;
                }
                else if(strcmp(client_cmd,"quit")==0)
                {
                    printf("quit\n");
                    goto endchild;
                }
                else  
                {
                    printf("bad request!\n");
                    goto loop;
                }
            }
endchild:
            printf("connection closed.\n");
            close(datasock);
            close(msgsock);
            exit(0);
        }
         
      }
   }while(TRUE);
 
   exit(0);
}

//pwd command
void cmd_pwd(int sock)
{
    int len;
    memset(currentDirPath,0,sizeof(currentDirPath));
    getcwd(currentDirPath,sizeof(currentDirPath));
    char *savePointer=getDirName(currentDirPath);
    strcpy(currentDirName,savePointer);
    len=strlen(currentDirName)+1;
    write(sock,currentDirName,len);
}

//dir command
void cmd_dir(int sock)
{
    DIR *pdir; //目录结构
    char fileName[30];
    char fileInfo[50];
    int i, fcounts=0, len;
    struct dirent *pent;//目录的结构体属性
    int fd;
    struct stat fileSta;//文件属性
    char filePath[200];
    
    pdir=opendir(currentDirPath);//打开目录
    pent=readdir(pdir);//读取目录
    
    while(pent!=NULL)
    {
        fcounts++;//计算文件个数
        pent=readdir(pdir);
    }

    write(sock,&fcounts,sizeof(int));//将文件个数写入sock
    closedir(pdir);//关闭目录

    if(fcounts<=0)
    {
        return;
    }
    else
    {
        pdir=opendir(currentDirPath);
        for(i=0;i<fcounts;i++)
        {
            pent=readdir(pdir);
            memset(fileName,0,30);
            memset(fileInfo,0,sizeof(fileInfo));
            strcpy(fileName,pent->d_name);
            
            //check the file is a directory or a file
            memset(filePath,0,sizeof(filePath));
            strcpy(filePath,currentDirPath);
            strcat(filePath,"/");//链接两个字符串
            strcat(filePath,fileName);
            fd=open(filePath,O_RDONLY, S_IREAD);
            
            fstat(fd,&fileSta);//用来读取打开的文件的属性,stat用来读取没有打开的文件的属性
            if(S_ISDIR(fileSta.st_mode))//判断文件是否为目录
            {
                strcat(fileInfo,"dir\t");
                strcat(fileInfo,fileName);
            }
            else
            {    
                strcat(fileInfo,"file\t");
                strcat(fileInfo,fileName);
            }
            write(sock,fileInfo,sizeof(fileInfo));
        }
        closedir(pdir);
    }
    
    
}

//command cd
void cmd_cd(int sock,char *dirName)
{
    DIR *pdir;
    struct dirent *pent;
    char filename[30];
    int i,fcounts=0;
    int flag=0;

    pdir=opendir(currentDirPath);
    pent=readdir(pdir);
    
    while(pent!=NULL)
    {
        fcounts++;
        pent=readdir(pdir);
    }

    closedir(pdir);

    if(fcounts<=0)
    {
        return;
    }
    else
    {
        pdir=opendir(currentDirPath);
        for(i=0;i<fcounts;i++)
        {
            pent=readdir(pdir);
            if(strcmp(pent->d_name,dirName)==0)
            {
                strcat(currentDirPath,"/");
                strcat(currentDirPath,dirName);
                flag=1;
                break;
            }
        }
        
        if(flag==1)
        {
            write(sock,currentDirPath,sizeof(currentDirPath));
        }
        closedir(pdir);
    }
    
    
}

//command cd..
void cmd_cdback(int sock)
{
    int len;
    int i, record;

    len=strlen(currentDirPath);
    
    for(i=len-1;i>=0;i--)
    {
        if(currentDirPath[i]=='/')
        {
            currentDirPath[i]='\0';
            break;
        }
        currentDirPath[i]='\0';
    }
}
//command ?
void cmd_help(int sock)
{
    int len=strlen(help)+1;
    write(sock,help,len);
}

//command get
void cmd_get(int sock,char*fileName)
{
    int fd;
    struct stat fileSta;
    long fileSize;
    char filePath[200], buf[dataLen];
    
    memset(filePath,0,sizeof(filePath));
    strcpy(filePath,currentDirPath);
    strcat(filePath,"/");
    strcat(filePath,fileName);

    fd=open(filePath,O_RDONLY, S_IREAD);
    if(fd!=-1)
    {
        fstat(fd,&fileSta);
        fileSize=(long) fileSta.st_size;//?
        write(sock,&fileSize,sizeof(long));
        memset(buf,0,dataLen);
        while(fileSize>dataLen)
        {
            read(fd,buf,dataLen);
            write(sock,buf,dataLen);
            fileSize=fileSize-dataLen;
        }
        
        read(fd,buf,fileSize);
        write(sock,buf,fileSize);
        close(fd);
        printf("transfer completed\n");
    }
    else
    {
        printf("open file %s failed\n",filePath);
    }    
}

//command put
void cmd_put(int sock,char *fileName)
{    
    int fd;
    long fileSize;
    
    char filePath[200], buf[dataLen];
    strcpy(filePath,currentDirPath);
    strcat(filePath,"/");
    strcat(filePath,fileName);
    

    fd=open(filePath,O_RDWR|O_CREAT, S_IREAD|S_IWRITE);
    if(fd!=-1)
    {    
        memset(buf,0,dataLen);
        read(sock,&fileSize,sizeof(long));

        while(fileSize>dataLen)
        {
            read(sock,buf,dataLen);
            write(fd,buf,dataLen);
            fileSize=fileSize-dataLen;
        }
        
        read(sock,buf,fileSize);
        write(fd,buf,fileSize);
        close(fd);
        printf("transfer completed\n");
    }
    else
    {
        printf("open file %s failed\n",filePath);
    }
    
}

//get the last string after the last char '/'
char *getDirName(char *dirPathName)
{
    int i, pos, len;
    char *dirName;

    if(dirPathName==NULL)
    {
        printf("directory absoultly path is null!\n");
        return NULL;
    }    
    
    len=strlen(dirPathName);
    for(i=len-1;i>=0;i--)
    {
        if(dirPathName[i]=='/')
        {
            pos=i;
            break;
        }
    }
    
    dirName=(char *)malloc(len-pos+1);
    for(i=pos+1;i<len;i++)
    {
        dirName[i-pos-1]=dirPathName[i];    
    }
    
    return dirName;
}
客户端实现:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>

#define TRUE 1
#define dataLen 1024
char user_cmd[10],cmd_arg[20];
char buf[dataLen];

void cmd_pwd(int sock,int sockmsg);
void cmd_dir(int sock,int sockmsg);
void cmd_cd(int sock,int sockmsg,char *dirName);
void cmd_cdback(int sock,int sockmsg);
void cmd_help(int sock,int sockmsg);
void cmd_get(int sock,int sockmsg,char *fileName);
void cmd_put(int sock,int sockmsg,char *fileName);
void cmd_quit(int sock,int sockmsg);
 
int main(int argc,char *argv[])
{
  int cmd_len,arg_len;
  int sock, sockmsg;
  struct sockaddr_in server, servermsg;
  struct hostent *hp;
  
  sock=socket(AF_INET,SOCK_STREAM,0);
  sockmsg=socket(AF_INET,SOCK_STREAM,0);
     
  if (sock<0||sockmsg<0)
  {
    perror("opening stream socket");
    exit(1);
  }
 
  hp = gethostbyname(argv[1]);
  if (hp==0)
  {
    fprintf(stderr,"%s:unknown host\n",argv[1]);
    exit(2);
  }
 
  server.sin_family=AF_INET;
  server.sin_port=htons(atoi(argv[2]));
  memcpy((char*)&server.sin_addr, (char*)hp->h_addr, hp->h_length);
 
  servermsg.sin_family=AF_INET;
  servermsg.sin_port=htons(atoi(argv[2])+1);
  memcpy((char*)&servermsg.sin_addr, (char*)hp->h_addr, hp->h_length);
 
  if (connect(sock,(struct sockaddr *)&server,sizeof server)<0||connect(sockmsg,(struct sockaddr *)&servermsg,sizeof servermsg)<0)
  {
     perror("connecting stream socket");
    exit(1);
  }
 
 
  //Get command from command line and do just the action
  while(TRUE)
  {
    memset(user_cmd,0,10);
    memset(cmd_arg,0,20);

    //First get the input character by user
    printf("command: ");
    scanf("%s",user_cmd);
    cmd_len=strlen(user_cmd);
    //Then get the command character and the argument
    if(strcmp(user_cmd,"quit")==0)        //command "quit"
    {
        cmd_quit(sock,sockmsg);
        close(sockmsg);
        close(sock);
        printf("connection closed\n\n");
        exit(0);
    }     
    else if(strcmp(user_cmd,"?")==0)      //command "?"
    {
        cmd_help(sock,sockmsg);
    }
    else if(strcmp(user_cmd,"pwd")==0)     //command "pwd"
    {
        cmd_pwd(sock,sockmsg);
    }
    else if(strcmp(user_cmd,"dir")==0)      //command "dir"
    {
        cmd_dir(sock,sockmsg);
    }
    else if(strcmp(user_cmd,"cd")==0)    //commad "cd"
    {
        //input command argument
        scanf("%s",cmd_arg);
        cmd_cd(sock,sockmsg,cmd_arg);
    }
    else if(strcmp(user_cmd,"cd..")==0)
    {
        cmd_cdback(sock,sockmsg);
    }
    else if(strcmp(user_cmd,"get")==0)    //command "get"
    {
        //input command argument
        scanf("%s",cmd_arg);
        cmd_get(sock,sockmsg,cmd_arg);
    }
    else if(strcmp(user_cmd,"put")==0)    //command "put"
    {   
        //input command argument
        scanf("%s",cmd_arg);
        cmd_put(sock,sockmsg,cmd_arg);
    }
    else
    {
        printf("bad command!\n");
    }
  } 
 
}

//command pwd
void cmd_pwd(int sock,int sockmsg)
{
    //int numRead;
    char dirName[30];
    write(sockmsg,user_cmd,sizeof(user_cmd));
    read(sock,dirName,30);
    printf("%s\n",dirName);
}

//command dir
void cmd_dir(int sock, int sockmsg)
{
    int i, fileNum=0;
    char fileInfo[50];
   
    write(sockmsg,user_cmd,sizeof(user_cmd));
    read(sock,&fileNum,sizeof(int));

    printf("--------------------------------------------------------\n");
    printf("file number : %d\n",fileNum);
    if(fileNum>0)
    {
        for(i=0;i<fileNum;i++)
        {
            memset(fileInfo,0,sizeof(fileInfo));
            read(sock,fileInfo,sizeof(fileInfo));
            printf("%s\n",fileInfo);
        }
        printf("--------------------------------------------------------\n");
    }
    else if(fileNum==0)
    {
        printf("directory of server point is empty.\n");
        return;
    }
    else
    {
        printf("error in command 'dir'\n");
        return;
    }
}

//command cd
void cmd_cd(int sock,int sockmsg,char *dirName)
{
    char currentDirPath[200];
    write(sockmsg,user_cmd,sizeof(user_cmd));
    write(sockmsg,cmd_arg,sizeof(cmd_arg));
    read(sock,currentDirPath,sizeof(currentDirPath));
   
    printf("now in directory : %s\n",currentDirPath);
}

//command cd..
void cmd_cdback(int sock,int sockmsg)
{
    write(sockmsg,user_cmd,sizeof(user_cmd));   
}
//command quit
void cmd_quit(int sock,int sockmsg)
{
    write(sockmsg,user_cmd,sizeof(user_cmd));
}

//command help
void cmd_help(int sock, int sockmsg)
{
    char help[300];
    write(sockmsg,user_cmd,sizeof(user_cmd));
    read(sock,help,300);
   
    printf("%s\n",help);   
}

//command get
void cmd_get(int sock,int sockmsg,char *fileName)
{
    int fd;
    long fileSize;
    char localFilePath[200];

    write(sockmsg,user_cmd,sizeof(user_cmd));
    write(sockmsg,cmd_arg,sizeof(cmd_arg));
    printf("%s\n%s\n",user_cmd,cmd_arg);
   
    memset(localFilePath,0,sizeof(localFilePath));
    getcwd(localFilePath,sizeof(localFilePath));
    strcat(localFilePath,"/");
    strcat(localFilePath,fileName);

    fd=open(localFilePath,O_RDWR|O_CREAT, S_IREAD|S_IWRITE);
    if(fd!=-1)
    {   
        memset(buf,0,dataLen);
        read(sock,&fileSize,sizeof(long));
        while(fileSize>dataLen)
        {
            read(sock,buf,dataLen);
            write(fd,buf,dataLen);
            fileSize=fileSize-dataLen;
        }
       
        read(sock,buf,fileSize);
        write(fd,buf,fileSize);
        close(fd);
        printf("download completed\n");
    }
    else
    {
        printf("open file %s failed\n",localFilePath);
    }
}

//command put
void cmd_put(int sock,int sockmsg,char* fileName)
{   
    write(sockmsg,user_cmd,sizeof(user_cmd));
    write(sockmsg,cmd_arg,sizeof(cmd_arg));
   
    int fd;
    long fileSize;
    int numRead;
    char filePath[200];
    struct stat fileSta;

    memset(filePath,0,sizeof(filePath));
    getcwd(filePath,sizeof(filePath));
   
    strcat(filePath,"/");
    strcat(filePath,fileName);
   
    fd=open(filePath,O_RDONLY, S_IREAD);

    if(fd!=-1)
    {
        fstat(fd,&fileSta);
        fileSize=(long) fileSta.st_size;

        write(sock,&fileSize,sizeof(long));
        memset(buf,0,dataLen);
        while(fileSize>dataLen)
        {
            read(fd,buf,dataLen);
            write(sock,buf,dataLen);
            fileSize=fileSize-dataLen;
        }
       
        read(fd,buf,fileSize);
        write(sock,buf,fileSize);
        close(fd);
        printf("upload completed\n");
    }
    else
    {
        printf("open file %s failed\n",filePath);
    }   
}

posted @ 2010-12-17 14:27  flyxiang  阅读(865)  评论(0编辑  收藏  举报