利用TCP编程实现FTP功能

news2024/11/13 10:02:13
模拟FTP核心原理:客户端连接服务器后,向服务器发送一个文件。文件名可以通过参数指定,服务器端接收客户端传来的文件(文件名随意),如果文件不存在自动创建文件,如果文件存在,那么清空文件然后写入。

项目功能介绍:
均有服务器和客户端代码,基于TCP写的。
在同一路径下,将客户端可执行代码复制到其他的路径下,接下来在不同的路径下运行服务器和客户端。相当于另外一台电脑在访问服务器。
客户端和服务器链接成功后出现以下提示:四个功能
***************list**************//列出服务器所在目录下的普通文件名
***********put filename**********//从客户端所在路径上传文件
***********get filename**********//从服务器所在路径下载文件
**************quit***************//退出(可只退出客户端,服务器等待下一个客户端链接)

思路:

list:客户端输入list------》把list发送给服务器-------》接收list---》判断是否为list----》目录操作(循环读目录文件)--------》判断是否为普通文件-----》如果是普通文件就发送给客户端------》发送一个结束“end”的标志----------》客户端循环接收普通文件并打印到终端显示

put filename:客户端输入put 文件名---》把put 文件名发送给服务器---》接收put 文件名---》判断是否为put -----》(cp:源文件再客户端所在路径下,目标文件在服务器所在路径下)客户端循环读源文件发送给服务器,服务器循环接收写到目标文件里--------》发送一个结束“end”的标志

接收大小与发送大小一致(避免沾包)

客户端:

#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
void show()
{
    printf("***************list**************\n");
    printf("***********put filename**********\n");
    printf("***********get filename**********\n");
    printf("**************quit***************\n");
}
int list(int acceptfd)
{
    char buf[128];
    int ret;
    while (1)
    {
        ret = recv(acceptfd, buf, sizeof(buf), 0);
        if (ret < 0)
        {
            printf("recv err\n");
            return -1;
        }
        else if (ret == 0)
        {
            printf("client exit\n");
            return -1;
        }
        if (!strcmp(buf, "end"))
        {
            printf("\n");
            break;
        }
        printf("%s ", buf);
    }
}
int put(int sockfd, char *p)
{
    char buf[128];
    int fd = open(p + 4, O_RDONLY);
    if (fd < 0)
    {
        printf("open err\n");
        return -1;
    }
    while (read(fd, buf, sizeof(buf)-1))
    {
        send(sockfd, buf, sizeof(buf), 0);
        memset(buf, 0, sizeof(buf));
    }
    strcpy(buf, "over");
    send(sockfd, buf, sizeof(buf), 0);
    close(fd);
}
int get(int sockfd, char *p)
{
    char buf[128]={0};
    int fd = open(p + 4, O_WRONLY | O_CREAT | O_TRUNC ,0777);
    if (fd < 0)
    {
        printf("get open err\n");
        return -1;
    }
    while (1)
    {
        int ret = recv(sockfd, buf, sizeof(buf), 0);
        if (ret < 0)
        {
            perror("recv err");
            return -1;
        }
        else if (ret == 0)
        {
            printf("client exit\n");
            break;
        }
        if (!strcmp(buf, "over"))
            break;
        write(fd, buf, strlen(buf));
        memset(buf, 0, sizeof(buf));
    }
    close(fd);
}
int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    // 1.创建套接字(socket)------------》有手机
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }
    printf("sockfd:%d\n", sockfd);
    // 2.指定(服务器)网络信息--------》有对方的号码
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[1]));
    saddr.sin_addr.s_addr = inet_addr("192.168.50.241"); 
    //saddr.sin_addr.s_addr = INADDR_ANY;
    // 3.连接(connect)-------------------》拨打电话
    if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("connect err");
        return -1;
    }
    printf("connect okk\n");
    // 4.接收发送消息(recv send)---》通话
    show();
    while (1)
    {
        fgets(buf, sizeof(buf), stdin);
        if (buf[strlen(buf) - 1] == '\n')
            buf[strlen(buf) - 1] = '\0';
        send(sockfd, buf, sizeof(buf), 0);
        if (!strcmp(buf, "quit"))
            break;
        else if (!strcmp(buf, "list"))
            list(sockfd);
        else if (!strncmp(buf, "put ", 4))
            put(sockfd, buf);
        else if (!strncmp(buf, "get ", 4))
            get(sockfd, buf);
        else
            printf("命令无效,请重新输入\n");
        memset(buf,0, sizeof(buf));
        // write(sockfd, buf, sizeof(buf));
    }
    // 5.关闭套接字(close)------------》挂电话
    close(sockfd);
    return 0;
}

服务器:

#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
int list(int acceptfd)
{
    char buf[128];
    DIR *dr = opendir(".");
    if (dr == NULL)
    {
        printf("opendir err\n");
        return -1;
    }
    struct dirent *dir;
    while (dir = readdir(dr))
    {
        struct stat dir1;
        stat(dir->d_name, &dir1);
        if ((dir1.st_mode & __S_IFMT) == __S_IFREG)
        {
            strcpy(buf, dir->d_name);
            send(acceptfd, buf, sizeof(buf), 0);
            memset(buf, 0, sizeof(buf));
        }
    }
    strcpy(buf, "end");
    send(acceptfd, buf, sizeof(buf), 0);
    closedir(dr);
}
int get(int acceptfd, char *p)
{
    char buf[128];
    int fd = open(p + 4, O_RDONLY);
    if (fd < 0)
    {
        printf("open err\n");
        return -1;
    }
    while (read(fd, buf, sizeof(buf)))
    {
        send(acceptfd, buf, sizeof(buf), 0);
        memset(buf, 0, sizeof(buf));
    }
    strcpy(buf, "over");
    send(acceptfd, buf, sizeof(buf), 0);
    close(fd);
}
int put(int acceptfd, char *p)
{
    char buf[128] = {0};
    int fd = open(p + 4, O_WRONLY | O_CREAT | O_TRUNC, 0777);
    if (fd < 0)
    {
        printf("get open err\n");
        return -1;
    }
    while (1)
    {
        int ret = recv(acceptfd, buf, sizeof(buf), 0);
        if (ret < 0)
        {
            perror("recv err");
            return -1;
        }
        else if (ret == 0)
        {
            printf("client exit\n");
            break;
        }
        if (!strcmp(buf, "over"))
            break;
        write(fd, buf, strlen(buf));
        memset(buf, 0, sizeof(buf));
    }
    close(fd);
}
int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    int ret, acceptfd;
    // 1.创建套接字(socket)---------------》有手机
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }
    printf("sockfd:%d\n", sockfd); // 3
    // 2.指定网络信息---------------------------》有号码
    struct sockaddr_in saddr, caddr;
    saddr.sin_family = AF_INET;            // IPV4
    saddr.sin_port = htons(atoi(argv[1])); // 端口号
    saddr.sin_addr.s_addr = inet_addr("192.168.50.241"); // 虚拟机IP
    // saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    //saddr.sin_addr.s_addr = INADDR_ANY;
    int len = sizeof(caddr);
    // 3.绑定套接字(bind)------------------》绑定手机(插卡)
    if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("bind err");
        return -1;
    }
    printf("bind ok\n");
    // 4.监听套接字(listen)-----------------》待机
    if (listen(sockfd, 6) < 0)
    {
        perror("listen err");
        return -1;
    }
    printf("listen ok\n");
    // 5.接收客户端连接连接请求(accept)--》接电话
    // tcp服务器一共有两类文件描述符,一类用于连接,一类用于通信
    // socket函数返回值:用于连接的文件描述符
    // accept函数返回值:用于通信的文件描述符
    while (1)
    {

        acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
        if (acceptfd < 0)
        {
            perror("accept err");
            return -1;
        }
        printf("port:%d ip:%s\n", ntohs(caddr.sin_port), inet_ntoa(caddr.sin_addr));
        printf("acceptfd:%d\n", acceptfd);

        // 6.接收、发送数据(recv send)---》通话
        while (1)
        {
            // read/write()
            ret = recv(acceptfd, buf, sizeof(buf), 0);
            if (ret < 0)
            {
                perror("recv err");
                return -1;
            }
            else if (ret == 0)
            {
                printf("client exit\n");
                break;
            }
            if (!strcmp(buf, "list"))
                list(acceptfd);
            else if (!strncmp(buf, "get ", 4))
                put(acceptfd, buf);
            else if (!strncmp(buf, "put ", 4))
                put(acceptfd, buf);
        }
        close(acceptfd);
    }
    close(sockfd);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2119344.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uboot源码分析uboot启动流程,uboot-CMD命令调用关系

uboot的最终目的是引导启动内核加载系统&#xff0c;根据这个线索我们可以首先找到uboot引导内核的main函数&#xff0c;查看系统引导的执行跳转的函数 main_loop。 下面对uboot函数的调用关系和主要调用函数进行分析。 一、uboot函数调用关系梳理 函数调用如下&#xff1a; …

Ollama 本地运行大模型(LLM)完全指南

文章介绍了 Ollama 本地运行大模型&#xff08;LLM&#xff09;的方方面面&#xff0c; 包括安装运行、对话、自定义模型、系统提示配置、调试、开发、存储、如何作为服务、OpenAI 的兼容等。 这一年来&#xff0c;我已经习惯了使用线上大模型 API 来工作&#xff0c;只要网络…

2025毕业设计免费指导!!

本人专注于Android/java/PHP/Python/人工智能/数据库/微信小程序技术等领域的开发&#xff0c;以及有好几年的计算机毕业设计方面的实战开发经验和技术积累&#xff1b;尤其是在图像识别、网站开发和微信小程序的开发&#xff0c;很是熟悉和了解&#xff1b;本人也是多年的全栈…

DevOps实现CI/CD实战(六)- Jenkins集成k8s

十、 Jenkins集成k8s Jenkins在集成K8s之前&#xff0c;需要搭建k8s集群&#xff0c;具体搭建步骤&#xff0c;完整笔记 https://github.com/ITenderL/ITenderL.github.io/tree/main/docs/DevOps&#xff0c; 包括完整的DevOps的笔记。 1. 准备部署的yml文件 pipeline.yml …

祝福在茶礼丨酒茶香充满东方古韵特色的中秋礼盒,太惊艳了

中国是礼仪之邦&#xff0c;礼尚往来更是普通不过。象征东方古韵的茶礼成为现代送礼热门&#xff0c;尤其是逢年过节茶礼氛围更是浓郁&#xff0c;跃居礼单榜首。 中秋节作为团圆之节&#xff0c;送礼肯定少不了&#xff01;送茶礼的这几个理由你一定要知道&#xff01; 送茶即…

【动手学深度学习】06 矩阵计算(个人向笔记)

标量导数 这个比较简单&#xff0c;就是直接求导 亚导数 举了两个例子 梯度 下面是当 y 和 x 分别为向量和标量时求导的结果。一个为向量&#xff0c;一个为标量则结果为向量。两个都为向量结果为矩阵&#xff0c;两个都为标量结果为标量 当 y 为标量&#xff0c;x 为列…

关于腾讯IM消息ID不统一的问题?服务端的MsgKey和前端的msgID不一样

角色>前端&#xff1a;web、小程序、客户端&#xff08;ios、安卓&#xff09;&#xff1b;服务端&#xff1b;腾讯IM&#xff1b; 1、背景 IM消息ID不一致&#xff0c;本地没有缓存历史数据&#xff0c;导致在调用腾讯sdk方法时&#xff0c;id不一致报错问题 2、调研目的…

MySQL进阶篇4 - 锁

五、锁 5.1 概述 介绍 分类 5.2 全局锁 介绍 红色代表不可执行的操作&#xff0c;绿色代表可执行的操作 # mysqldump 是 MySQL 提供的数据备份的命令演示 # 如果想进行全库的逻辑备份&#xff0c;那么就需要在逻辑备份之前 # 手动的加上全局锁 flush tables with read …

flask下https教程

一、定义 linux 下flask https 协议 二、实现 linux 下flask https 协议 生成SSL证书和密钥文件。您可以使用工具如openssl来生成自签名SSL证书和密钥文件。运行以下命令生成证书和密钥文件&#xff1a; openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout…

HCIE和CCIE,哪个含金量更高点?

在现在内卷的大环境下&#xff0c;技术岗可谓人人自危&#xff0c;也因此各种认证的重视程度直线升高。 特别是华为认证的HCIE和思科认证的CCIE&#xff0c;它们都代表着网络技术领域的顶尖水平。 但面对这两个高含金量的认证&#xff0c;不得不让人问出这个问题&#xff1a;同…

找到办法了!一个站点,搞定所有访问权限需求

在知识库的构建与管理过程中&#xff0c;如何平衡信息的公开与私密性始终是一大挑战。传统方法往往需要建立多个具有不同访问权限的站点&#xff0c;操作繁琐且难以维护。尤其当企业需同时向公众和内部成员提供知识文章时&#xff0c;这一问题尤为突出。用户频繁反馈&#xff0…

振弦式渗压计安装流程全面指南

在大坝安全监测体系中&#xff0c;振弦式渗压计作为关键设备之一&#xff0c;承担着监测大坝内部渗流压力变化的重任。其安装质量直接关系到监测数据的准确性和大坝安全的评估。因此&#xff0c;制定一套科学、精细的安装流程&#xff0c;对于确保渗压计的正常运行和延长使用寿…

什么是生成式 AI?

人工智能 (AI) 通过使用机器学习与环境交互并执行任务来模仿人类行为&#xff0c;而无需明确指示要输出的内容。 生成式 AI 描述 AI 中用于创建原创内容的一类功能。 人员通常与聊天应用程序中内置的生成式 AI 交互。 此类应用程序的一个常见示例是 Microsoft Copilot&#xf…

Telephony STK 域选

在场测过程中,经常遇到STK功能不生效,点击STK会出现无响应的问题. 一般需要对比DUT和REF来确认问题所在。一般情况下,出现类似问题需要check是否域选是一致的。 测试机 对比机 对比机为展锐平台会出现弹框情况,从Log看,相关业务进行了报错回落,从IMS业务回落到了…

基于spring的博客系统(一)

通过前⾯课程的学习, 我们掌握了Spring框架和MyBatis的基本使⽤, 并完成了图书管理系统的常规功能 开发, 接下来我们系统的从0到1完成⼀个项⽬的开发&#xff1b; 1. 项⽬介绍 使⽤SSM框架实现⼀个简单的博客系统 共5个⻚⾯ 1. 用户登录 2. 博客发表⻚ 3. 博客编辑⻚ 4. 博客…

【Java算法】模拟

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【算法工作坊】算法实战揭秘 &#x1f9e3; 一.模拟算法 模拟算法和传统的算法有一些不同之处&#xff0c;更多的是对题目要求的理解&#xff0c;通过代码的方式去模拟实现一道题目在现实中的实现方法…

接口基础知识4概念纠正与补充说明

​接口基础知识4 1 请求方法的幂等性 幂等性的理解是没有问题的。但是请求方法和幂等性没有直接的关联。 在 REST API 设计中&#xff0c;幂等性非常重要&#xff0c;因为它保证了在重复请求的情况下&#xff0c;资源的状态始终保持一致&#xff0c;不会因为重复请求而发生副…

量化交易backtrader实践(一)_数据获取篇(1)_数据准备

我们需要使用backtrader来做量化交易回测&#xff0c;先解决一些前置问题&#xff1a; 需要回测哪几支股票&#xff0c;或者即时选取股票即时选取股票以什么形式&#xff0c;代码还是名称这些数据的格式是怎么样的&#xff0c;backtrader如何接收 在解决这些前置问题的过程中…

如何抽取一个特定页面从devExpress的例程集合中

https://download.csdn.net/download/haoyujie/89729356https://download.csdn.net/download/haoyujie/89729356相关资源。 devExpress界面库的例程的设计是有必要来吐槽的。其紧耦合和大捆绑&#xff0c;我认为是devExpress很重要的不友好&#xff0c;导致可用性差和学习曲线…

让AI算算国庆中秋,你究竟多休了几天

最近&#xff0c;2024年中秋和国庆的放假调休安排火速登上热搜&#xff1a; “上6休3&#xff0c;上3休2&#xff0c;上5休1&#xff0c;上2休7&#xff0c;再上5休1。” 是不是看着眼花缭乱&#xff1f;其实不仅你懵了&#xff0c;广大网友也集体抓狂&#xff1a;“这比高考…