基于tcp协议实现ftp功能

目录

引入

FTP简介

FTP优点

FTP前景

FTP通信流程

实现要求

示例代码片段

Makefile

server

client


引入

FTP简介

FTP(文件传输协议)是一种用于在计算机之间传输文件的标准网络协议。它允许用户通过客户端软件连接到远程服务器,同时进行文件的上传、下载、删除、重命名等操作。FTP通过建立一个客户端与服务器之间的连接,使用控制连接进行命令和状态传输,然后通过数据连接传输文件的实际内容。

FTP优点

FTP有许多优点,其中包括以下几点:

  1. 跨平台性:FTP是一种独立于操作系统的协议,可以在不同的操作系统上使用,如Windows、Mac、Linux等。

  2. 可靠性:FTP使用TCP/IP协议进行数据传输,具有数据可靠性和完整性的保证。

  3. 灵活性:FTP支持匿名访问和用户名/密码认证,可以根据需要进行身份验证。

  4. 文件管理:FTP提供了对远程服务器上文件的管理功能,用户可以在远程服务器上创建、删除、重命名文件夹和文件。

  5. 并发性:FTP支持多个客户端同时连接到服务器,并且可以同时进行多个文件传输操作。

FTP前景

FTP的前景在当前云计算和大数据时代非常广阔。尽管有许多其他的文件传输方式可供选择,如HTTP、SFTP等,但FTP仍然是广泛使用的标准协议之一。它被广泛应用于许多领域,如网站维护、文件共享、软件发布等。
随着云计算和虚拟化技术的发展,FTP也在不断演进和发展。FTP被集成到许多云存储解决方案中,提供高可用性、扩展性和安全性。同时,FTP协议也逐渐与其他技术集成,如SSH(Secure Shell),以提供更安全的文件传输。
尽管如今有许多新的文件传输协议和工具出现,但是由于FTP的成熟性和广泛适用性,它在短期内不大可能完全替代。然而,在未来,随着技术的不断发展和网络环境的变化,我们可能会看到FTP的功能和性能不断改进,以适应新的应用场景和需求。

FTP通信流程

以下是FTP的一般工作流程:
1、建立连接:客户端使用FTP客户端软件连接到FTP服务器;
2、身份验证:客户端在连接建立后,提供登录凭据;
3、导航文件系统:验证成功,客户端可以浏览FTP服务器上的文件系统,并选择要上传或下载的文件;
4、上传文件:客户端可以选择要上传到FTP服务器的本地文件,并将其发送到服务器;
5、下载文件:客户端可以选择要从FTP服务器下载的文件,并将其复制到本地计算机;
6、其他操作:FTP还支持其他操作,例如重命名文件、删除文件、创建文件夹等;

实现要求

1、服务器发送,一个或多个子客户端接收
2、服务器先开启子客户端才被允许接收
3、TCP通信

示例代码片段

Makefile

all:
	gcc server.c -o server	
	gcc client.c -o client
.PHONY:clean
clean:
	rm -f server client

server

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


void list_server(int acceptfd, char *buf, int size);
void put_server(int acceptfd, char *buf, int size);
void get_server(int acceptfd,char *buf, int size);


int main(int argc, char const *argv[])
{
    if (argc != 2)
    {
        printf("please input %s <port>\n", argv[0]);
        return -1;
    }
    // 创建流式套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket error..");
        return -1;
    }
    printf("sockfd:%d\n", sockfd); //3
    // ipv4
 
    struct sockaddr_in saddr, caddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[1]));
    saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
 
    socklen_t len = sizeof(caddr);
 
    // 绑定ip和端口
    if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("bind err.");
        return -1;
    }
    printf("bind ok.\n");
 
    // 监听
    if (listen(sockfd, 5) < 0)
    {
        perror("listen error..");
        return -1;
    }
    printf("listen ok.\n");
    // 阻塞等待
    while (1)
    {
        int acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
        if (acceptfd < 0)
        {
            perror("accept error..");
            return -1;
        }
        printf("acceptfd=%d\n", acceptfd);
        printf("client:ip=%s port=%d\n",
               inet_ntoa(caddr.sin_addr),
			   ntohs(caddr.sin_port));

        // 循环收发
        char buf[128];
        int ret;
        while (1)
        {
            ret = recv(acceptfd, buf, sizeof(buf), 0);
            if (ret < 0)
            {
                perror("recv err.");
                return -1;
            }
            else if (ret == 0)
            {
                printf("client exit\n");
                break;
            }
            else
            {
                if (strncmp(buf, "list", 4) == 0)
                { 
                    // 打开当前目录读文件判断文件是普通文件将文件名传给客户端
                    list_server(acceptfd, buf, sizeof(buf));
                }
                else if (strncmp(buf, "put ", 4) == 0)
                { 
                    // 打开新建文件接收客户端发送过来的内容写到文件
                    put_server(acceptfd, buf, sizeof(buf));
                }
                else if (strncmp(buf, "get ", 4) == 0)
                {   
                    // 发送文件
                    // 打开文件读文件内容发送给客户端
                    get_server(acceptfd, buf, sizeof(buf));
                }
            }
        }
        close(acceptfd);
    }
    close(sockfd);
    return 0;
}
 
// get
void get_server(int acceptfd,char *buf, int size) //buf->put xxx.c
{
    // 打开文件
    int fd = open(buf + 4, O_RDONLY);
    if (fd < 0)
    {
        perror("open file error..");
        return;
    }
    int ret;
    while ((ret = read(fd, buf, size - 1)) != 0)
    {
        buf[ret] = '\0';
        send(acceptfd, buf, size, 0);
    }
    strcpy(buf, "get success..");
    send(acceptfd, buf, size, 0);
}

// 接收文件
void put_server(int acceptfd, char *buf, int size)
{
	// 打开文件
    int fd = open(buf + 4, O_TRUNC | O_CREAT | O_WRONLY, 0666);
    if (fd < 0)
    {
        perror("open error..");
        return;
    }
    while (1)
    {
		// 接收数据
        if (recv(acceptfd, buf, size, 0) < 0)
        {
            perror("recv error..");
            return;
        }
        if (strncmp(buf, "put success..", 7) == 0)
            break;
		// 数据写入
        write(fd, buf, strlen(buf));
    }
}
 
// list
void list_server(int acceptfd, char *buf, int size)
{
    DIR *dir = opendir("./");
    if (dir == NULL)
    {
        perror("opendir error..");
        return;
    }
    struct dirent *dp = NULL;
    struct stat st;
    while ((dp = readdir(dir)) != NULL)
    {
        // dp->d_name拿到的文件名
        // 判断文件属性stat
        stat(dp->d_name, &st);
        if (S_ISREG(st.st_mode))
        {
            strcpy(buf, dp->d_name);	
            send(acceptfd, buf, size, 0);
        }
    }
    // 发送结束标志
    strcpy(buf, "list success..");
    send(acceptfd, buf, size, 0);
}

client

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


void show(void);
void list_client(int sockfd, char *buf, int size);
void put_client(int sockfd, char *buf, int size);
void get_client(int sockfd, char *buf, int size);


int main(int argc, char const *argv[])
{
    if (argc != 3)
    {
        printf("please input %s <ip> <port>\n", argv[0]);
        return -1;
    }
    // 创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket error..");
        return -1;
    }
    printf("socket create success..");
    // ipv4
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[2]));
    saddr.sin_addr.s_addr = inet_addr(argv[1]);
    if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("connect error..");
        return -1;
    }

    // 收发消息
    char buf[128];
    while (1)
    {
        // 请求
        show();
        // 循环获取
        fgets(buf, sizeof(buf), stdin);
        if (buf[strlen(buf) - 1] == '\n')
            buf[strlen(buf) - 1] = '\0';
		
        send(sockfd, buf, sizeof(buf), 0);
		
        if (strncmp(buf, "list", 4) == 0)
        { 	
            // 循环接收服务器发送过来的普通文件名输出到终端
            list_client(sockfd, buf, sizeof(buf));
        }
        else if (strncmp(buf, "put ", 4) == 0)
        { 	
            // 上传文件
            put_client(sockfd,buf,sizeof(buf));
        }
        else if (strncmp(buf, "get ", 4) == 0)
        { 	
            // 下载服务器路径下的文件
        	// 打开新建文件接收服务器发送过来的内容写到文件
            get_client(sockfd,buf,sizeof(buf));
        }
        else if (strncmp(buf, "quit", 4) == 0)
        {
            break;
        }
    }
    close(sockfd);
    return 0;
}

// get
void get_client(int sockfd, char *buf, int size)
{
    int fd = open(buf + 4, O_TRUNC | O_CREAT | O_WRONLY, 0666);
    if (fd < 0)
    {
        perror("open error..");
        return;
    }
    while (1)
    {
        if (recv(sockfd, buf, size, 0) < 0)
        {
            perror("recv err.");
            return;
        }
        if (strncmp(buf, "get success..", 7) == 0)
            break;
        write(fd, buf, strlen(buf));
    }
}
// put
void put_client(int sockfd, char *buf, int size)
{
    // 打开文件
    int fd = open(buf + 4, O_RDONLY);
    if (fd < 0)
    {
        perror("open file error..");
        return;
    }
    int ret;
    while ((ret = read(fd, buf, size - 1)) != 0)
    {
        buf[ret] = '\0';
        send(sockfd, buf, size, 0);
    }
    strcpy(buf, "put success..");
    send(sockfd, buf, size, 0);
}
 
// list
void list_client(int sockfd, char *buf, int size)
{
 
    while (1)
    {
        if (recv(sockfd, buf, size, 0) < 0)
        {
            perror("list recv error..");
            return;
        }
        if (strncmp(buf, "list ok.", 8) == 0)
        {
            break;
        }
        printf("%s\n", buf);
    }
}
 
void show(void)
{
    printf("************list***************\n");
    printf("************put filename*******\n");
    printf("************get filename*******\n");
    printf("************quit***************\n");
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值