Linux系统编程,使用C语言实现简单的FTP(服务器/客户端)

这篇具有很好参考价值的文章主要介绍了Linux系统编程,使用C语言实现简单的FTP(服务器/客户端)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

跟着上官社长 陈哥花了一个月的时间终于把Linux系统编程学的差不多了,这一个月真的是头疼啊,各种bug,调的真心心累,不过好在问题都解决掉了,在此也感谢一下答疑老师,给我提供了很多的思路,本文章是对前段时间学习Linux,做一个小小的总结,才疏学浅,只学到这个地步,下来继续努力,加油!。

一.基本功能

  1. get + xxx 从服务器获取某个文件到客户端。

  1. put + xxx 把客户端的某个文件上传到服务器。

  1. cd + 路径 切换目录

  1. lls 列出本地文件列表

  1. ls 列出服务端文件列表

  1. lcd +路径 切换本地目录

二.实现思路

1.使用socket先把服务器和客户端建立连接

c语言实现ftp客户端,linux,服务器,c语言,Powered by 金山文档

2.建立连接后开始信息的交互

客户端输入指令服务器处理指令

三.具体代码如下

先建立socket连接,如下是服务器的代码。

int main(int argc,char**argv)
{
    if(argc !=3 )//判断参数是否输入正确
    {
        printf("input errror\n");    
        exit(-1);
    }
    int s_fd = socket(AF_INET,SOCK_STREAM,0);//创建网络套接字

    struct sockaddr_in addr;
    struct sockaddr_in addr2;
    
     memset(&addr,0,sizeof(struct sockaddr_in));
     memset(&addr2,0,sizeof(struct sockaddr_in));
    int n_read;
    addr.sin_family = AF_INET;//地址协议族
    addr.sin_prot = htons(atoi(argv[2]));//端口号,先使用atoi函数把参数转换成整型,在使用htons转为网络字节序。
    inet_aton(argv[1], &s_addr.sin_addr);//IP地址,使用inet_aton函数把点分十进制的IP地址,转换为网络字节序。例如,192.168.147.155.
    bind(s_fd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in));

    listen(s_fd,10);//监听

    int sz = sizeof(struct sockaddr_in);
    while(1)//循环卡住不让退出去。
    {
        int c_fd = accept(s_fd,(struct sockaddr *)&addr2,&sz);//尝试连接
        if(c_fd == -1)
        {
            perror("accept");
            exit(-1);    
        }
        printf("get connect : %s\n",inet_nota(addr2.sin_addr));//连接成功打印对方的IP地址。
      
    }
        return 0;
    }

客服端代码,如下

int main(int argc,char **argv)
{
    int c_fd;
    struct Msg msg;

    struct sockaddr_in c_addr;
    memset(&c_addr,0,sizeof(struct sockaddr));

    // 1. socket
    c_fd = socket(AF_INET,SOCK_STREAM,0);
    if(c_fd==-1)
    {
        perror("socket:");
        exit(-1);
    }
    c_addr.sin_family = AF_INET;
    c_addr.sin_port =htons(atoi(argv[2]));
    inet_aton(argv[1], &c_addr.sin_addr);
    connect(c_fd,(struct sockaddr*)&c_addr,sizeof(struct sockaddr_in));//请求连接
    printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));//连接成功打印IP
    while(1)
    {
    }
    return 0;
}

上面只是服务器和客户端,建立连接的代码,还不携带参数,下面开始客户端和服务器进行通讯。

四.服务器/客户端通讯

1.服务器和客户端共有的文件

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

#define LS   0
#define PWD  1
#define GET  2
#define IFGO 3
#define CD   4
#define PUT  5
#define LLS  6
#define LCD  7
#define LPWD 8
#define QUIT 9
#define DOFILE 10

struct Msg
{
        int type;
        char data[1024];
        char buf[128];
};

2.客户端


int get_cmd_type(char *cmd)
{
     //比较输入的指令,找到对应的就返回相对应的指令。
     if(!strcmp("ls",cmd))      return LS;
     if(!strcmp("lls",cmd))     return LLS;
     if(!strcmp("pwd",cmd))     return PWD;
     if(!strcmp("quit",cmd))    return QUIE;
      //在输入的指令字符串里面找,对应的指令
      if(strstr(cmd."cd"))       return CD;
      if(strstr(cmd,"get"))      return GET;
      if(strstr(cmd,"put"))      return PUT;

       return -1;//未找到返回错误
}




char *getdir(char *cms)//分割指令,来获取参数
{
    char *p = NULL;
     p = strtok(cms," ");
     p = strtok(NULL," ");
    return p;
}



int cmd_handler(struct Msg msg,int fd)
{
    int ret;
    char buf[100];//临时空间
    char *dir = NULL;
    int filefd; //文件表示符
    ret = get_cmd_type(msg.data);//输入的指令转换成整数
    switch(ret)//根据ret的值来选择
    {
        case PWD:
        case LS:
        case CD:
                msg.type = 0;//标记符
                write(fd,msg.data,sizeof(msg));//发送命令
                break;
       
        case GET:
                msg.type = 2;
                write(fd,msg.data,sizeof(msg));//发送命令
                break;
        case PUT:
                strcpy(buf,msg.data);
                dir = getdir(buf);
                if(access(dir,F_OK) == -1)//判断参数文件是否存在
                 {    
                        printf("%s not exsit\n",dir);
                  }
                  else//如果存在
                  {
                        filefd = open(dir,O_RDWR);//打开这个文件
                        read(filefd,msg.buf,sizeof(msg.buf));//读取这个文件
                        close(filefd);//关闭这个文件
        
                        write(fd,msg,data,sizeof(msg));//向服务器发送命令
                   }
                
         case QUIT:
                   strcpy(msg.data,"quit");
                   write(fd,msg.data,sizeof(msg));
                   close(fd);//关闭文件
                   exit(-1);//退出程序
         case LLS:
                   system("ls");
                   break;
         case LCD:
                    dir = getdir(msg.data);
                    chdir(dir);
                    break;
    }
    return ret;
}


void hand_sever_message(int c_fd,struct Msg msg)
{
    struct Msg msgget;
    char *dir = NULL;
    int n_read;
    n_read = read(c_fd,&msgget,sizeof(msgget));//客户端执行到这里时,会阻塞在这,等待服务器写入数据
    if(n_read == -1)
    {
        printf("server out \n");
        exit(-1);    
    }
    else if(msg.type == DOFILE)
     {
        dir = getdir(msg.data);
        int filefd = open(dir,O_RDWR|O_CREAT,0666);
         write(filefd,msgget.data,strlen(msgget.data));
        putchar('>');
        fflush(stdout);
     }
    else
    {
        printf("============================\n");
        printf("\n%s\n",msgget.data);
        printf("=============================\n");
        putchar('>');
        fflush(stdout);
    }
}



int main(int argc,char **argv)
{
    int c_fd;
    int ret;
    struct Msg msg;//定义结构体
    struct sockaddr_in c_addr;
    memset(&c_addr,0,sizeof(struct sockaddr));//初始化结构体里的内容

    
    c_fd = socket(AF_INET,SOCK_STREAM,0);//创建socket
    if(c_fd==-1)
    {
        perror("socket:");
        exit(-1);
    }
    c_addr.sin_family = AF_INET;
    c_addr.sin_port =htons(atoi(argv[2]));
    inet_aton(argv[1], &c_addr.sin_addr);

    connect(c_fd,(struct sockaddr*)&c_addr,sizeof(struct sockaddr_in));//请求连接
    printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));//连接成功打印IP
    while(1)
    {
        memset(msg.data,0,sizeof(msg.data));
        scanf("%[\n]",msg.data);//获取客户端指令
        if(strlen(msg.data) == 0)
        {
            if(mark == 1)
            {
                printf(">");
            }
        }
        ret = cmd_handler(msg,c_fd);//封装一个函数,处理指令
        
        if(ret >IFGO)
        {
            putchar('>');
            fflush(stdout);
            continue;
        }
        if(ret == -1)
        {
            printf("commend out\n");
            printf(">");
            fflush(stdout);
        }
        handler_sever_message(c_fd,msg);//处理客户端返回内容 
    }
    close(c_fd);//关闭文件
    return 0;
}

3.服务器


int get_cmd_type(char *cmd)//把指令转换成整型
{
    if(!strcmp("ls",cmd))  return LS;
    if(!strcmp("quit",cmd)) return QUIT;
    if(!strcmp("pwd",cmd))  return PWD;
    if(strstr(cmd,"cd")!=NULL)  return CD;
    if(strstr(cmd,"get")!=NULL) return GET;
    if(strstr(cmd,"put")!=NULL) return PUT;
    return -1;
}

char *getdir(char cmd)//分割指令,获取第二个参数
{
    char *p = NULL;
    p = strtok(cmd," ");
    p = strtok(NULL," ");
    return p;
}


void msg_handler(struct Msg msg,int fd)
{
    int ret;
     char *dir;
    char *databuf[1024] = {0};//临时空间
    int fdfile;//文件描述符
    ret = get_cmd_type(msg.data);

    switch(ret)
            case LS:
            case PWD:
                    msg.type = 0
                    FILE *r = popen(msg.data,"r");执行该参数,并读取,返回读取文件的指针
                    fread(msg.data,sizeof(msg.data),1,r);读取到data空间里面,读取一次,读取的文件是上面r指向的文件。
                    write(fd,msg.data,sizeof(msg));读取完成后写入。
                    break;
            case CD:
                   dir = getdir(msg.data);//先把指令分割出来,获取参数
                    printf("dir :%s\n",dir);//打印参数
                    chdir(dir); 将当前目录改向参数指向的目录。
                    break;
            case GET:
                    dir = getdir(msg.data);//获取参数文件
                    if(access(dir,F_OK)== -1)//判断文件存在吗
                     {
                            strcpy(msg.data,"NO this file");
                      }
                      else//如果存在
                       {
                            msg.type = DOFILE; //标记
                            fdfile = open(dir,O_RDWR);//打开此文件
                            read(fdfile,databuf,sizeof(databuf));//读取此文件到临时空间databuf里面
                            close(fdfile);//读取完成,关闭此文件
                            strcpy(msg.data,databuf);//将databuf拷贝
                            write(fd,msg.data,sizeof(msg));//写入
                       }
                    break;

            case PUT:
                    dir = getdir(msg.data);//分割获取第二个参数
                   fdfile =  open(dir,O_RDWR|O_CREAT,0666);//打开该参数的文件
                    write(fd,msg.buf,strlen(msg.buf));//将客户端读取的内容写入服务器
                    close(fdfile);//写完关闭文件
                    break;
            case QUIT:
                    printf("client quit\n");//打印退出信心
                    exit(-1);//退出程序

}
int main(int argc,char**argv)
{
    if(argc !=3 )//判断参数是否输入正确
    {
        printf("input errror\n");    
        exit(-1);
    }
    int s_fd = socket(AF_INET,SOCK_STREAM,0);//创建网络套接字
    struct Msg msg;
    struct sockaddr_in addr;
    struct sockaddr_in addr2;
    
     memset(&addr,0,sizeof(struct sockaddr_in));
     memset(&addr2,0,sizeof(struct sockaddr_in));
    int n_read;
    addr.sin_family = AF_INET;//地址协议族
    addr.sin_prot = htons(atoi(argv[2]));//端口号,先使用atoi函数把参数转换成整型,在使用htons转为网络字节序。
    inet_aton(argv[1], &s_addr.sin_addr);//IP地址,使用inet_aton函数把点分十进制的IP地址,转换为网络字节序。例如,192.168.147.155.
    bind(s_fd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in));

    listen(s_fd,10);//监听

    int sz = sizeof(struct sockaddr_in);
    while(1)//循环卡住不让退出去。
    {
        int c_fd = accept(s_fd,(struct sockaddr *)&addr2,&sz);//尝试连接
        if(c_fd == -1)
        {
            perror("accept");
            exit(-1);    
        }
        printf("get connect : %s\n",inet_nota(addr2.sin_addr));//连接成功打印对方的IP地址。
        if(fork()== 0)//创建子进程来对接,进行通讯
        {
                memset(msg.data,0,sizeof(msg.date));
                n_read =read(c_fd,&msg,sizeof(msg));//读取客户端发过来的消息
                if(n_read == 0)//判断读取信息
                {
                    printf("client out\n");
                    break;
                }else (if n_read>0)//如果读取到了
                {
                msg_hanfler(msg,c_fd);//处理函数
                }
        }
      
    }
        return 0;
}

以上就是我对这段时间学习Linux的理解,希望可以帮助到大家谢谢文章来源地址https://www.toymoban.com/news/detail-524810.html

到了这里,关于Linux系统编程,使用C语言实现简单的FTP(服务器/客户端)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 如何在 Ubuntu Linux 中设置和使用 FTP 服务器?

    注:本文假设您已在 Ubuntu Linux 系统上安装并配置好了适当的环境。 FTP(文件传输协议)是一种常用的网络协议,用于在客户端和服务器之间进行文件传输。在 Ubuntu Linux 中,您可以设置和使用 FTP 服务器,以便通过网络与其他设备共享文件。本文将详细介绍如何在 Ubuntu Lin

    2024年02月05日
    浏览(52)
  • 简单FTP客户端软件开发——搭建FTP服务器

    计网课程设计的要求是: 1) 该FTP客户端程序具有以下基本功能: 2) 开发美观易用的图形界面 FTP使用客户服务器方式,因为开发的是客户端,所以需要一个FTP服务器,客户端进行连接访问,进行文件操作。 前面我们已经安装好了Linux虚拟机,在Linux搭建FTP服务器原参考博客

    2024年02月03日
    浏览(69)
  • Ubuntu系统下c语言的简单编程

    本文主要讲述关于在ubuntu系统下编程c语言的流程,包括网络设置、apt源的更换、简单的c语言在Linux和Windows下的对比以及用Makelife编写上述程序。 准备一台PC机并安装好Vmware(笔者采用的是15.5版本),我们使用 NetworkManager 进行网络配置。 1.将虚拟机网络适配器调为桥接模式 选择

    2023年04月12日
    浏览(36)
  • 《Linux操作系统编程》第九章 数据查找和筛选工具 : 了解流编辑器sed和报表生成器awk的简单使用

    🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍》学会IDEA常用操作,工作效率翻倍~💐 🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬

    2024年02月12日
    浏览(54)
  • 网络编程套接字(二)之UDP服务器简单实现

    目录 一、服务端UdpServer 1、udp_server.hpp 1、服务器的初始化 2、服务器的运行 2、udp_server.cc 二、客户端UdpClient udp_client.cc 三、完整代码 首先,我们在该文件中,将服务器封装成一个类,而作为一款服务器,必须要有自己的端口号,同时网络服务器需要有对应的IP地址,文件描述

    2024年04月16日
    浏览(57)
  • 【网络编程】实现一个简单多线程版本TCP服务器(附源码)

    accept 函数是在服务器端用于接受客户端连接请求的函数,它在监听套接字上等待客户端的连接,并在有新的连接请求到来时创建一个新的套接字用于与该客户端通信。 下面是 accept 函数的详细介绍以及各个参数的意义: sockfd: 是服务器监听套接字的文件描述符,通常是使用

    2024年02月13日
    浏览(53)
  • C#实现简单TCP服务器和客户端网络编程

    在C#中进行网络编程涉及许多类和命名空间,用于创建和管理网络连接、传输数据等。下面是一些主要涉及的类和命名空间: System.Net 命名空间: 这个命名空间提供了大部分网络编程所需的类,包括: IPAddress :用于表示IP地址。 IPEndPoint :表示IP地址和端口号的组合。 Socke

    2024年02月11日
    浏览(63)
  • 【手把手做ROS2机器人系统开发五】使用C++实现编写简单的服务器和客户端

    目录 使用C++实现编写简单的服务器和客户端 一、程序编写 1、创建软件包  2、编译软件包 3、软件配置 4、服务器程序编写 5、客户端程序编写 6、软件包设置 7、设置编译选项 二、程序测试 1、编译程序 2、开启节点测试运行 3、执行效果展示          上一讲我们讲解了如

    2024年02月10日
    浏览(43)
  • UDP数据报网络编程(实现简单的回显服务器,客户端)

           回显服务器表示客户端发的是啥,服务器就返回啥,主要是为了熟悉UDP数据报网络编程的基本步骤         对于程序的所有分析都写到了代码上 当我们用idea实现了上面的代码后可以通过idea如何开启多个客户端(一个代码开启多个客户端运行)来检验多个客户端向

    2024年02月13日
    浏览(62)
  • 【Linux】FTP文件服务器

    FTP (File transfer protocol) 是TCP/IP 协议组中的协议之一。他最主要的功能是在服务器与客户端之间进行文件的传输。FTP就是实现两台计算机之间的拷贝,从远程计算机拷贝文件至自己的计算机上,称之为“下载 (download)”文件。将文件从自己计算机中拷贝至远程计算机上,则称

    2024年02月10日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包