linux下基于tcp的FTP编程

来源:互联网 发布:如何清理地图数据 编辑:程序博客网 时间:2024/06/08 19:09

客户端输入:

ls :           显示本地文件列表

service  ls:       显示服务器文件列表

upload  xxx:      实现xxx文件读取与上传

download  xxx :  实现xxx文件下载与存储


公共函数commonfunc.c 代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "commonfunc.h"
#include <stddef.h>
#include <dirent.h>


#define BACKLOG 10//最大连接数


/******************函数作用:网络初始化*****************/
int network_init(int net_type, const char* NET_IP, short NET_NUM)
{
    int sockfd;
    if(-1 == (sockfd = socket(PF_INET, SOCK_STREAM, 0)))   //创建监听套接字
    {
        perror("Create socket error!");
        //exit(EXIT_FAILURE);
        return -1;
    }


    struct sockaddr_in sockadd;
    memset(&sockadd, 0, sizeof(sockadd));
    sockadd.sin_family = AF_INET;
    sockadd.sin_port = htons(NET_NUM);
    sockadd.sin_addr.s_addr = inet_addr(NET_IP);


    if(NET_CLIENT == net_type)
    {
           //连接服务器
        if(-1 == connect(sockfd, (struct sockaddr*)(&sockadd),\
        sizeof(sockadd)))
        {
            perror("Connect error!");
            //exit(EXIT_FAILURE);
            return -1;
        }
    }
    else
    {
        if(NET_SERVER == net_type)
        {
                //绑定IP地址端口号
            if(-1 == bind(sockfd, (struct sockaddr*)(&sockadd),\
            sizeof(sockadd)))
            {
                perror("Bind error!");
                return -1;
            }
            
            if(-1 == listen(sockfd, BACKLOG))   //监听客户端
            {
                perror("Listen error!");
                return -1;
            }
        }
        else
        {
            return -1;
        }
    }
    return sockfd;
}


/**************************命令解析函数************************/
int ftp_cmd_analyse(const char* cmd)
{
    if(NULL == cmd)
    {
        return CMD_ERROR;
    }
    else
    {
          if(0 == strncmp(cmd, "ls",2))   //列出本地文件列表指令
                    return CMD_LS;
           else
              {
            if(0 == strncmp(cmd, "server ls", 9))   //列出服务器文件列表指令
                return CMD_SERVER_LS;
              else
               {
                if(0 == strcmp(cmd, "quit"))   //断开链接指令
                    return CMD_QUIT;
                else
                  {
                      if(0 == strncmp(cmd, "download ", 9))    //从服务器下载文件指令
                      return CMD_DOWNLOAD;
                    else
                    {
                        if(0 == strncmp(cmd, "upload ", 7))    //上传文件到服务器指令
                            return CMD_UPLOAD;
                        else
                        {
                            return CMD_ERROR;
                        }
                    }
                }
            }   
        }
    }
}


/****************从服务器端获取文件列表函数********************/
int ftp_getlist(int getsockfd)
{
    char GET_BUFF[BUFF_LEN];
    int readsize;
    sprintf(GET_BUFF,  "server ls");
     if(-1 == write(getsockfd, GET_BUFF, BUFF_LEN))   //向服务器发送命令
    {
        perror("Send cmd error!");
        return -1;
    }
    else
    {
        while(1)   //循环读取
        {
            readsize = read(getsockfd, GET_BUFF, BUFF_LEN);
            if(readsize <= 0)   //读错误
            {
                perror("Get list error!");
                return -1;
            }
            else
            {
                if(0 == strncmp(GET_BUFF, GET_LIST_END, \
                sizeof(GET_LIST_END)))   //判断服务器是否发送完毕
                {
                  break;   //发送完毕,退出
                }
                else
                {
                    printf("%s\n", GET_BUFF);   //服务器端发送完毕,显示文件
                }
            }
        }
    }
    return getsockfd;
}


/**************把服务器端文件列表发送到客户端函数**************/
int ftp_putlist(int putsockfd)
{
    const char* LIST_NAME=".";
    char PUT_BUFF[BUFF_LEN];
    int strn, strm;
    DIR* dp;
    struct dirent *ep;
    struct stat st;
    char LIST_PATH[256];




    dp = opendir(LIST_NAME);   //打开目录


    if(NULL != dp)   //打开目录成功
    {
        while(ep = readdir(dp))   //循环读目录
        {
            if(ep->d_name[0] != '.')   //如果不是隐藏文件或目录
            {
                 sprintf(PUT_BUFF,"%s",ep->d_name);
                 write(putsockfd, PUT_BUFF, BUFF_LEN);
            }
           
        }


        if(-1 == write(putsockfd, GET_LIST_END, BUFF_LEN))   //发送结束
        {
            perror("Write endstring error!");
            return -1;
        }
    }
    else
    {
        if(-1 == write(putsockfd, GET_LIST_END, BUFF_LEN))   //发送结束
        {
            perror("Write endstring error!");
            return -1;
        }
        perror("Can't open the directory!");
        return -1;
    }


    closedir(dp);
    return putsockfd;
}


/*************************文件接收函数*************************/
int ftp_getfile(int getsockfd, const char* GET_FILENAME)
{
    int getfilefd;   //存放接收文件的文件描述符
    int getfilesize;   //实际接收的文件大小
    char GET_BUFF[BUFF_LEN];   //接收缓存




    //打开一个文件描述符用与保存来自发送端的文件
    if(-1  == (getfilefd = open(GET_FILENAME, O_WRONLY|O_CREAT|O_TRUNC, 0666)))
    {
        perror("Can't open or creat file!");
        return -1;
    }
    else
    {
        while(getfilesize = read(getsockfd, GET_BUFF, BUFF_LEN) > 0)     //接收文件
        {
            
            if(0 == strncmp(GET_BUFF, "ERROR:", 6))   //接收文件出错
            {
                printf("%s", GET_BUFF);
                return -1;
            }
            else
            {
                  //取出数据包头中包含的数据区大小
                memcpy(&getfilesize, GET_BUFF, 4);


                /*GET_BUFF+4是因为数据包前四个字节存放的是数据长度,之后的
                1024个字节才存放的实际的数据*/
                if(-1 == write(getfilefd, GET_BUFF+4, getfilesize))
                {
                    perror("Download error!");   //接收出错,返回
                    close(getfilefd);   //关闭文件
                    return -1;
                }
                if(getfilesize < (BUFF_LEN-4))   //已经读取到文件末尾
                        break;   //接收结束,退出
            }
        }
        close(getfilefd);   //关闭文件
        return getfilefd;   //接收完成,返回接收到的文件的文件描述符。
       
    }
}


/*****************************文件发送函数********************************/
int ftp_putfile(int putsockfd, const char* PUT_FILENAME)
{
    int putfilefd;   //存放接收文件的文件描述符
    int putfilesize;   //实际接收的文件大小
    char PUT_BUFF[BUFF_LEN];    


    if(-1 == (putfilefd = open(PUT_FILENAME, O_RDONLY)))   //打开文件
    {
        perror("Open error!");
        write(putsockfd, E_NOFILE, BUFF_LEN);   //把错误信息写回。
        /*如果不写回错误信息,发送端会卡死*/
        return -1;
    }
    else
    {
       
      while((putfilesize = read(putfilefd, PUT_BUFF+4, (BUFF_LEN-4))) \
        >0)
        {
            memcpy(PUT_BUFF, &putfilesize, 4);
            if(-1 == write(putsockfd, PUT_BUFF, BUFF_LEN))
            {
                perror("Put file error!");
                close(putfilefd);
                return -1;
            }
            memset(PUT_BUFF, 0, BUFF_LEN);   //清空缓冲区
        }
    }
    close(putfilefd);
    return putfilefd;
}


//////////////////////////////////////////////////公共函数commonfunc.h头文件////////////////////////////////////////////////////


#ifndef __NETWORK_H_
#define __NETWORK_H_


#define NET_SERVER  11
#define NET_CLIENT  22


#define BUFF_LEN 1028//接收发送缓冲区大小


#define CMD_LS         11//列出客户端所有文件
#define CMD_SERVER_LS  22//列出服务器所有文件
#define CMD_DOWNLOAD   33//下载文件
#define CMD_UPLOAD     44//上传文件
#define CMD_QUIT       55//退出
#define CMD_ERROR      -1//错误


#define E_NOFILE    "ERROR:No such file or directory!\n"
#define E_DODNLOAD  "ERROR:Download error!\n"
#define E_UPLOAD    "ERROR:Upload error!\n"
#define GET_LIST_END "SUCCESS:GET LIST SUCCESS!"


int     network_init(int net_type, const char* IP_ADDRESS, \
short INET_NUM);


void    ftp_print_help(void);
int     ftp_cmd_analyse(const char* cmd);
int     ftp_getlist(int getsockfd);
int     ftp_putlist(int putsockfd);
int     ftp_getfile(int getsockfd, const char* GET_FILENAME);
int     ftp_putfile(int putsockfd, const char* PUT_FILENAME);

#endif

//////////////////////////////////////////////////////////////////////客户端程序///////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "commonfunc.h"
#include <dirent.h>


#define INET_NUM 8888   //端口号
#define IP_ADDRESS "10.104.6.110"   //服务器IP


#ifndef BUFF_LEN
#define BUFF_LEN 1028
#endif


#define CMD_LS         11//列出客户端所有文件
#define CMD_SERVER_LS  22//列出服务器所有文件
#define CMD_DOWNLOAD   33//下载文件
#define CMD_UPLOAD     44//上传文件
#define CMD_QUIT       55//退出
#define CMD_ERROR      -1//错误




int main(void)
{
    int sockfd;
    DIR* dp;
    struct dirent *ep;
    sockfd = network_init(NET_CLIENT, IP_ADDRESS, INET_NUM);   //初始化网络连接
    if(sockfd == -1)
    {
        perror("Network init error!");
        exit(EXIT_FAILURE);
    }
    printf("Connect success!\n\n");
    printf("*********Operation Help*********\n");   //操作帮助
    printf("显示本地文件列表:        ls\n");
    printf("显示服务器文件列表:      server ls\n");
    printf("实现xxx文件读取与上传:   upload xxx\n");
    printf("实现xxx文件下载与存储:   download xxx\n");
    printf("断开socket链接:          quit\n");
    printf("*************************************\n\n");


    char SEND_BUFF[BUFF_LEN];   //发送数据缓冲区
    int cmd_result;   //存放命令解析结果
    while(1)
    {
        fgets(SEND_BUFF, sizeof(SEND_BUFF), stdin);   //输入命令
        SEND_BUFF[strlen(SEND_BUFF)-1] = '\0';   //去掉最后输入的回车符
        
        cmd_result = ftp_cmd_analyse(SEND_BUFF);   //解析输入的指令
        switch(cmd_result)
        {
            case CMD_ERROR:
                printf("ERROR!\n");
                break;
           
             ////////////////////////////////////////////////////////////
            case CMD_LS:    //列出本地文件列表
                 dp=opendir (".");
                 printf("*********File List of Client*********\n");
                while((ep = readdir(dp)))
                      {
                     if(ep->d_name[0] != '.')
                            {
                          printf("%s\n",ep->d_name);
                            }
                      }
                printf("*************************************\n");  
                printf("List file success!\n");      
               closedir(dp);
               break;
           ///////////////////////////////////////////////////////////
            case CMD_SERVER_LS:   //列出服务器端可下载的所有文件
                printf("*********File List of Server*********\n");
                if(ftp_getlist(sockfd) == -1)
                {
                    printf("List file error!\n");
                }
                else
                {          
                printf("*************************************\n");
                printf("List file success!\n");
                }
                break;
           
             ////////////////////////////////////////////////////////////
            case CMD_DOWNLOAD:   //从服务器下载文件
                if(write(sockfd, SEND_BUFF, BUFF_LEN) == -1)
                {
                    perror("Send cmd error!");
                    break;
                }
                if(ftp_getfile(sockfd, SEND_BUFF+9) == -1)   //下载文件
                {
                    printf("Download error!\n");
                }
                else
                {
                 printf("Download The File Success!!\n");
                }
                break;
            ////////////////////////////////////////////////////////////
            case CMD_UPLOAD:   //上传文件到服务器   
                 
                if(write(sockfd, SEND_BUFF, BUFF_LEN) == -1)
                {
                    perror("Send cmd error!");
                    break;
                }
                if(ftp_putfile(sockfd, SEND_BUFF+7) == -1)//上传文件
                {
                    printf("Upload error!\n");
                }
                else
                {
                    printf("Upload The File Success!!\n");
                }
                break; 
            ////////////////////////////////////////////////////////////
            case CMD_QUIT:   //断开连接
                printf("Welcome to use again!\nQUIT!\n");
                close(sockfd);//客户端关闭文件描述符后就会自动断开连接
                exit(EXIT_SUCCESS);
                break;
            ////////////////////////////////////////////////////////////
            default:
                break;
        }
    }
    close(sockfd);//客户端关闭文件描述符后就会自动断开连接
    return 0;
}


//////////////////////////////////////////////////////////////////////服务器程序///////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "commonfunc.h"


#define INET_NUM 8888   //端口号
#define IP_ADDRESS "10.104.6.110"   //IP地址


#define BUFF_LEN 1028


#define CMD_LS          11   //列出客户端所有文件
#define CMD_SERVER_LS   22   //列出服务器所有文件
#define CMD_DOWNLOAD    33   //下载文件
#define CMD_UPLOAD      44   //上传文件
#define CMD_QUIT        55   //退出
#define CMD_ERROR       -1   //错误




int main(void)
{
    int sockfd;   //网络套接字
    sockfd = network_init(NET_SERVER, IP_ADDRESS, INET_NUM);   //初始化网络连接
    if(sockfd == -1)
    {
        perror("Network init error!");
        exit(EXIT_FAILURE);
    }
    printf("LISTEN-ing...\n");


    char RCV_BUFF[BUFF_LEN];   //接收缓存
    char SEND_BUFF[BUFF_LEN];  //发送缓存
    int cmd_result;   //命令解析结果
    int connectfd;   //建立连接后用于通信的套接字文件
    int readlen;   //读取到的字节数
    while(1)
    {
        if((connectfd = accept(sockfd, NULL, NULL)) == -1)   //链接出错,给出提示
        {
            perror("Connect error!\n");
            break;
        }
        printf("Connect success!\n");
        while(1)
        {
            readlen = read(connectfd, RCV_BUFF, sizeof(RCV_BUFF));   //接收命令
            if(readlen <0)//接收出错
            {
                perror("Read error!\n");
                break;
            }
            else
            {
                if(readlen == 0)   //客户端关闭文件描述符后就会断开连接
                {
                    printf("Welcome to use again!\nQUIT...\n");
                    break;
                }
                else
                {
                    printf("**************************\n");
                    printf("RECV:%s\n",RCV_BUFF);
                    cmd_result = ftp_cmd_analyse(RCV_BUFF);   //解析命令
               switch(cmd_result)
                    {
                        case CMD_ERROR:
                            printf("CMD_ERROR!\n");
                            break;
                        case CMD_SERVER_LS:  //查看服务器文件列表
                            if(ftp_putlist(connectfd) == -1)
                            {
                                printf("List files error!\n");
                            }
                            else
                            {
                                printf("List files success!\n");
                            }
                            break;
                        case CMD_DOWNLOAD:   //客户端从服务器下载文件
                            printf("Put files:%s\n", RCV_BUFF+9);
                            if(ftp_putfile(connectfd, RCV_BUFF+9) == -1)
                            {
                                printf("Put files error!\n");
                            }
                            else
                            {
                                printf("Put files success!\n");
                            }
                            break;
                        case CMD_UPLOAD:   //客户端上传文件到服务器
                            printf("Get files:%s\n", RCV_BUFF+7);
                            if(ftp_getfile(connectfd, RCV_BUFF+7) == -1)
                            {


                                printf("Get files error!\n");
                            }
                            else
                            {
                                printf("Get files success!\n");
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
        }
        close(connectfd);//客户端退出,断开连接
    }
    close(sockfd);
    return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

原创粉丝点击