Linux 网络编程项目--简易ftp

主要代码

config.h


#define LS     0
#define GET    1
#define PWD    2#define IFGO   3#define LCD    4
#define LLS    5
#define CD     6
#define PUT    7#define QUIT   8
#define DOFILE 9struct  Msg
{int type;char data[1024];char secondBuf[128];
};

服务器:

#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
// #include<linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "config.h"
#include <sys/stat.h>
#include <fcntl.h>int get_cmd_type(char *cmd)
{if (!strcmp("ls", cmd))return LS; // 这里类命令没有参数直接strcmp 比较即可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;
}char *getDesDir(char *cmsg) // 获取后段字符串 --- 参数
{char *p = strtok(cmsg, " ");p = strtok(NULL, " ");return p;
}void msg_handler(struct Msg msg, int fd)
{char dataBuf[1024] = {0};char *file = NULL;int fdfile;printf("cmd: %s\n", msg.data);int ret = get_cmd_type(msg.data);switch (ret){ // 根据返回的指令选择,处理的方式case LS:case PWD:// popen() 函数通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程。FILE *r = popen(msg.data, "r");fread(msg.data, sizeof(msg.data), 1, r);write(fd, &msg, sizeof(msg)); // 写入socket通道的 fdbreak;case CD:char *dir = getDesDir(msg.data);printf("dir: %s\n", dir);chdir(dir);break;case GET:msg.type=DOFILE;file = getDesDir(msg.data);  获取后段字符串 --- 参数 -文件名if (access(file, F_OK) == -1){                                       // access 判断文件是否存在strcpy(msg.data, "No this  file!"); 将 "no this file"的信息写入data,并且write返回给客户端write(fd, &msg, sizeof(msg));}else{// 存在,打开服务器目录下的文件,读取里面的内容,写入到客户端文件中fdfile = open(file, O_RDWR);            // 打开服务器目录下的文件read(fdfile, dataBuf, sizeof(dataBuf)); // 读取里面的内容close(fdfile);                          // 用完记得关闭文件strcpy(msg.data, dataBuf);    // 写入数据write(fd, &msg, sizeof(msg)); // 写入到客户端文件中}break;case PUT:                                                       // 上传文件到服务器fdfile = open(getDesDir(msg.data), O_RDWR | O_CREAT, 0666); // 以可读可写的形式创建 需要put的文件,给0666的权限 -- 可读可写write(fdfile, msg.secondBuf, strlen(msg.secondBuf));         向新创建的文件中写入数据,secondBufclose(fdfile);break;case QUIT:puts("Client Quit!");exit(-1);}
}int main(int argc, char **argv)
{int s_fd;int c_fd;struct sockaddr_in s_addr;struct sockaddr_in c_addr;int nread;// char msg[128]={0};struct Msg msg;char readBuf[128] = {0};if (argc != 3){ // 判断传参是否正确puts("Improper parameters");exit(-1);}memset(&s_addr, 0, sizeof(struct sockaddr_in));memset(&c_addr, 0, sizeof(struct sockaddr_in));int clen = sizeof(struct sockaddr_in);// 1. socket -- IPv4  流形式i 0 --默认 TCPs_fd = socket(AF_INET, SOCK_STREAM, 0);if (s_fd == -1){perror("socket");exit(-1);}// 初始化bind需要的structs_addr.sin_family = AF_INET;// htons -- h - host to  ns-net shorts_addr.sin_port = htons(atoi(argv[2])); // 通过传参指定端口// a -- ASCLL  传参方式得到IPinet_aton(argv[1], &s_addr.sin_addr);// 3.bindbind(s_fd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr_in));// listenlisten(s_fd, 10);// 4.acceptwhile (1){c_fd = accept(s_fd, (struct sockaddr *)&c_addr, &clen); // 获得新的客户端 描述符if (c_fd == -1){perror("accept");}printf("get connect. %s\n", inet_ntoa(c_addr.sin_addr));if (fork() == 0){ // 接入新的客户端 创建子进程来处理读while (1){// read()memset(msg.data, 0, sizeof(msg.data));nread = read(c_fd, &msg, sizeof(msg));if (nread == 0){printf("client  out\n"); // 读取时已经到达文件的末尾,则返回0。表示客户端退出break;}else if (nread > 0) // 读取成功{msg_handler(msg, c_fd);}}}}close(c_fd);close(s_fd);return 0;
}

客户端:

#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
// #include<linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "config.h"
#include <sys/stat.h>
#include <fcntl.h>int get_cmd_type(char *cmd)
{if (strstr(cmd, "lcd"))return LCD;if (strstr(cmd, "cd"))return CD;if (strstr(cmd, "get"))return GET;if (strstr(cmd, "put"))return PUT;if (!strcmp("quit", cmd))return QUIT;if (!strcmp("ls", cmd))return LS;if (!strcmp("lls", cmd))return LLS;if (!strcmp("pwd", cmd))return PWD;return -1; //  找不到这个指令就放回-1
}char *getdir(char *cmsg) // 获取后段字符串 --- 参数
{char *p = strtok(cmsg, " ");p = strtok(NULL, " ");return p;
}int cmdHanler(struct Msg msg, int fd)
{char buf[32];char *dir = NULL;int ret;int fdfile;ret = get_cmd_type(msg.data);switch (ret){case LS:case CD:case PWD:write(fd, &msg, sizeof(msg));break;case GET:write(fd, &msg, sizeof(msg));break;case PUT:strcpy(buf, msg.data);dir = getdir(buf);if (access(dir, F_OK) == -1){printf("%s not exit\n", dir);}else{fdfile = open(dir, O_RDWR);read(fdfile, msg.secondBuf, sizeof(msg.secondBuf));  客户端把数据读到secondBuf里面close(fdfile);write(fd, &msg, sizeof(msg)); // 将内容写给服务器fd}break;case LLS:system("ls");break;case LCD:dir = getdir(msg.data);chdir(dir);break;case QUIT:strcpy(msg.data, "quit");write(fd, &msg, sizeof(msg));close(fd);exit(-1);}
return ret;
}void  handlerServerMessage(int c_fd,struct Msg msg){int nread;struct Msg msgget;int newfdfile;nread=read(c_fd,&msgget,sizeof(msgget));if(nread==0){printf("server is out,quit\n");exit(-1);}else if(msgget.type == DOFILE){char *p=getdir(msg.data);newfdfile=open(p,O_RDWR|O_CREAT,0600); write(newfdfile,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;struct sockaddr_in c_addr;struct Msg msg;int nread;if (argc != 3){ // 判断传参是否正确puts("Improper parameters");exit(-1);}// char msg[128] = {0};char readBuf[128];memset(&c_addr, 0, sizeof(struct sockaddr_in));int clen = sizeof(struct sockaddr_in);// 1. socket -- IPv4  流形式i 0 --默认 TCPc_fd = socket(AF_INET, SOCK_STREAM, 0);if (c_fd == -1){perror("socket");exit(-1);}// 初始化bind需要的structc_addr.sin_family = AF_INET;// htons -- h - host to  ns-net shortc_addr.sin_port = htons(atoi(argv[2]));// a -- ASCLLinet_aton(argv[1], &c_addr.sin_addr);// 2.connect -- 阻塞等待连接int p_c = connect(c_fd, (struct sockaddr *)&c_addr, sizeof(struct sockaddr_in));if (p_c == -1){perror("connect");exit(-1);}printf("get connect. %s\n", inet_ntoa(c_addr.sin_addr));while (1){ // 我们希望能一直读写 -- 实现聊天功能memset(msg.data, 0, sizeof(msg.data));gets(msg.data); // 一直 获取 命令输入int ret = cmdHanler(msg, c_fd);if (ret > IFGO){putchar('>');fflush(stdout);continue;}if (ret == -1){puts("command not");putchar('>');fflush(stdout);continue;}handlerServerMessage(c_fd, msg);}return 0;
}

代码解析:

基本命令

如下图: 

我们在客户端中将LS PWD CD命令写入msg,到服务器这边就会读取他们的值

msg.data 的第一段子串是命令,第二串是参数 -- 比如 cd .. 

ls,pwd只有命令,调用popen来调用

popen()函数补充



  popen() 函数通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程。

  这个进程必须由 pclose() 函数关闭,而不是 fclose() 函数。pclose() 函数关闭标准 I/O 流,等待命令执行结束,然后返回 shell 的终止状态。如果 shell 不能被执行,则 pclose() 返回的终止状态与 shell 已执行 exit 一样。

也就是,popen创建管道,执行shell命令将文件流中的某些数据读出

get

服务器先将文件写入msg

客户端再通过msg获取

 //这个函数用来读取我们的文件指令

 if 类型是文件操作 FOFILE,就创建创建文件向其中写入数据,这样就得到了服务器的文件 --GET

else 直接将操作打印出来 


 

put:

如下图,先从客户端开始说,客户端先确保,文件存在,然后将文件打开,将文件内容读取到secondBuf里面,关文件,写入fd(服务器)的msg中。

服务器,直接创建一个文件来接收我们刚刚传过来的数据,写入文件,关文件。

_access()函数补充


头文件:#include<io.h>
函数原型:int _access(const char *pathname, int mode);
参数:pathname 为文件路径或目录路径,mode 为访问权限
返回值:如果文件具有指定的访问权限,则函数返回0;如果文件不存在或者不能访问指定的权限,则返回-1

lcd:

读取到dir 为第二个子串 -- 参数

调用chdir 跳转即可

chdir()函数 补充


系统调用 chdir()和 fchdir()可以用于更改进程的当前工作目录,函数原型如下所示:

#include <unistd.h>

int chdir(const char *path);
int fchdir(int fd);

首先,使用这两个函数之一需要包含头文件<unistd.h>
函数参数和返回值含义如下:
path:将进程的当前工作目录更改为 path 参数指定的目录,可以是绝对路径、也可以是相对路径,指定的目录必须要存在,否则会报错。
fd:将进程的当前工作目录更改为 fd 文件描述符所指定的目录(譬如使用 open 函数打开一个目录)。
返回值:成功均返回 0;失败均返回-1,并设置 errno。

// 其余细节,还请读者看代码注释

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

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

相关文章

【天软行业全景画像】报告第8期

行业全景画像因子 报告概要&#xff1a;传媒、环保、机械设备行业的拥挤度较高&#xff0c;实际投资交易应注意&#xff1b;煤炭、银行、石油石化行业动量较强&#xff0c;医药生物、综合、计算机行业动量较弱&#xff0c;业绩整体表现较差&#xff1b;食品饮料、公用事业行业景…

书生·浦语大模型实战营(第二期):XTuner 微调 LLM

目录 Finetune简介两种Finetune范式一条数据的一生标准格式数据添加对话模板两种finetune的loss计算 LoRA&QLoRA XTunerXTuner简介XTuner快速上手安装&训练配置模板对话工具数据处理数据集映射函数 InternLM2 1.8B模型多模态LLM给LLM装上电子眼&#xff1a;多模态LLM原…

技术速递|为 .NET iOS 和 .NET MAUI 应用程序添加 Apple 隐私清单支持

作者&#xff1a;Gerald Versluis 排版&#xff1a;Alan Wang Apple 正在推出一项隐私政策&#xff0c;将隐私清单文件包含在针对 App Store 上的 iOS、iPadOS 和 tvOS 平台的新应用程序和更新应用程序中。请注意&#xff0c;至少目前 macOS 应用程序被排除在外。 隐私清单文件…

el-table-column叠加el-popover使用

需求&#xff1a;el-table-column有一列展示多个tag信息&#xff0c;实现点击tag展示tag信息以及tag对应的详细信息 table的数据格式 data:[{...,isPopoverVisible:false,},{...,isPopoverVisible:false,},... ]写法&#xff1a; <el-table-column label"配置信息&q…

死磕GMSSL通信-C/C++系列(一)

死磕GMSSL通信-C/C++系列(一) 最近再做国密通信的项目开发,以为国密也就简单的集成一个库就可以完事了,没想到能有这么多坑。遂写下文章,避免重复踩坑。以下国密通信的坑有以下场景 1、使用GMSSL guanzhi/GmSSL进行通信 2、使用加密套件SM2-WITH-SMS4-SM3 使用心得 ​…

【个人博客搭建】(3)添加SqlSugar ORM 以及Json配置文件读取

1、安装sqlsugar。在models下的依赖项那右击选择管理Nuget程序包&#xff0c;输入sqlsugarcore&#xff08;因为我们用的是netcore&#xff0c;而不是net famework所以也对应sqlsugarcore&#xff09;&#xff0c;出来的第一个就是了&#xff0c;然后点击选择版本&#xff0c;一…

ABAP 提示框 汇总

文章目录 前言 1.POPUP_TO_DISPLAY_TEXT 2.POPUP_TO_CONFIRM 3.G_DISPLAY_SELECTION_DYNPRO 4.REUSE_ALV_POPUP_TO_SELECT 5.POPUP_TO_DECIDE_LIST 6.POPUP_WITH_TABLE_DISPLAY_OK 7.BKK_POPUP_DISPLAY_LIST 8. POPUP_TO_CONFIRM_WITH_MESSAGE 9.POPUP_TO_CONFIRM 1…

MinIO + Prometheus + Grafana docker部署

文章目录 说明MinIO简介MinIO 容器化部署Prometheus服务地址配置方法一&#xff1a;先部署后修改方法二&#xff1a;部署时修改compose文件&#xff08;未验证&#xff09; MinIO Access Key配置Prometheus 容器化部署MinIO 生成抓取配置修改Prometheus配置文件Grafana 容器化部…

python3.poc。sqlmapTamperPocsuite

目的&#xff0c;掌握工具的api接口&#xff0c;框架工具二次开发 ---sqlmap的api接口&#xff1a;https://www.freebuf.com/articles/web/204875.html 应用&#xff1a;配合前期信息收集的到可能存在注入点的地方&#xff0c;批量化的去扫描 #开发当前项目过程&#xff1a…

YOLOv8改进 | Conv篇 | CVPR2024最新DynamicConv替换下采样(包含C2f创新改进,解决低FLOPs陷阱)

一、本文介绍 本文给大家带来的改进机制是CVPR2024的最新改进机制DynamicConv其是CVPR2024的最新改进机制,这个论文中介绍了一个名为ParameterNet的新型设计原则,它旨在在大规模视觉预训练模型中增加参数数量,同时尽量不增加浮点运算(FLOPs),所以本文的DynamicConv被提出…

华为OD-C卷-靠谱的车[100分]C语言-100%

题目描述 程序员小明打了一辆出租车去上班。出于职业敏感,他注意到这辆出租车的计费表有点问题,总是偏大。 出租车司机解释说他不喜欢数字4,所以改装了计费表,任何数字位置遇到数字4就直接跳过,其余功能都正常。 比如: 23再多一块钱就变为25;39再多一块钱变为50;399…

VictoriaMetrics安装部署

安装部署 1、 去 vm release 下载编译好的二进制版本&#xff0c;比如我们选择下载 v1.69.0 amd64。 2、 解压缩后得到&#xff1a; $ ls -l vm*-prod -rwxr-xr-x 1 work work 10946416 Nov 8 22:03 vminsert-prod* -rwxr-xr-x 1 work work 13000624 Nov 8 22:03 vmselect…

书生·浦语大模型全链路开源体系-第6课

书生浦语大模型全链路开源体系-第6课 书生浦语大模型全链路开源体系-第6课相关资源Lagent & AgentLego 智能体应用搭建环境准备创建虚拟环境安装LMDeploy安装 Lagent安装 AgentLego Lagent 轻量级智能体框架使用 LMDeploy 部署启动并使用 Lagent Web Demo使用自定义工具获取…

倾斜摄影技术的特点及应用有哪些?

倾斜摄影测量技术&#xff08;Oblique Photogrammetry&#xff09;是一种通过使用倾斜角度相机拍摄图像的方法来进行测量和建模的技术。与传统的垂直摄影测量技术不同&#xff0c;倾斜摄影测量技术通过使用摄影机倾斜角度相对于垂直方向较大的角度来拍摄图像&#xff0c;从而能…

博客系统ssm

.博客功能 主要功能实现 首页有最新文章排版&#xff0c;最新评论留言&#xff0c;每日一言&#xff0c;标签云&#xff0c;网站信息等等文章模块有文章分类&#xff0c;归档&#xff0c;标签等功能&#xff0c;支持点击进入相应文章&#xff0c;都支持评论留言友链支持一些大佬…

ospf综合路由实验

1配置ip 2配置私网通&#xff08;配置双向验证&#xff09; 3配置静态缺省,公网通&#xff08;nat配置后因为没有缺省所以通不了&#xff0c;要么配置缺省要么配置特殊区域自动下发缺省&#xff09;配置mgre 4链路聚合&#xff0c;配置特殊区域&#xff0c;更改hello更新时间 …

基于Material Design风格开源、易用、强大的WPF UI控件库

前言 今天大姚给大家分享一款基于Material Design风格开源、免费&#xff08;MIT License&#xff09;、易于使用、强大的WPF UI控件库&#xff1a;MaterialDesignInXamlToolkit。 项目介绍 MaterialDesignInXamlToolkit 是一个开源、易于使用、强大的 WPF UI 控件库&#x…

OpenHarmony多媒体-mp4parser

简介 一个读取、写入操作音视频文件编辑的工具。 编译运行 1、通过IDE工具下载依赖SDK&#xff0c;Tools->SDK Manager->Openharmony SDK 把native选项勾上下载&#xff0c;API版本>10 2、开发板选择RK3568&#xff0c;ROM下载地址. 选择开发板类型是rk3568&#xf…

美团财务科技Java后端一面:面向对象、类加载过程、全限定类名相同的类是否可以同时被加载

更多大厂面试内容可见 -> http://11come.cn 美团财务科技Java后端一面&#xff1a;面向对象、类加载过程、全限定类名相同的类是否可以同时被加载 如何理解面向对象&#xff1f; 面向对象 是具有对象概念的编程范式&#xff0c;面向对象将程序实现分为了一个个独立的对象&…

Liunx常用命令

Liunx常用命令 1、less less 是一个用于查看文件内容的终端分页器&#xff0c;它允许您以一页一页的方式浏览文件内容&#xff0c;并提供了多种交互方式来进行导航和搜索。 以下是一些 less 命令的常用用法&#xff1a; 启动 less&#xff1a; less filename这将在终端中打开指…