Linux下 Socket服务器和客户端文件互传

目录

1.项目描述

2.函数准备

2.1 gets函数

2.2 popen函数、fread函数

 2.3 access 函数

 2.4 exit 函数

 2.5 strtok 函数

2.6 chdir函数

3.项目代码

3.1服务器代码

3.2客户端代码

4.问题总结


1.项目描述

基于Soket聊天服务器,实现服务器和客户端的文件传输。

Linux系统下建立Socket聊天服务器_趣知boy的博客-CSDN博客

ls   获取服务器文件列表   
pwd  获取服务器当前路径
cd   对服务器目录的操作  +dir
quit 退出连接  put 上传文件到服务器  +file_name
get 获取服务器数据    +file_namelcd 对客户端目录的操作 +dir
lls 列出客户端所有文件 dofile 创建文件  

项目结构

2.函数准备

2.1 gets函数

gets 从标准输入流(通常是键盘)读取一行字符串,并将其存储在指定的字符数组中。

其比较重要的一个功能是阻塞

   printf("请输入您的姓名:");gets(name);printf("您的姓名是:%s\n", name);

2.2 popen函数、fread函数

size_t fread(void *ptr, size_t size, size_t count, FILE *stream);

 该函数可以读取指定数量(count = 1)的元素,每个元素的大小为size个字节,从指定文件(stream)中读取到内存指针(ptr)所指的位置。 

 2.3 access 函数

用于判断文件或目录是否具有某种权限。

int access(const char *pathname, int mode);
F_OK:检查文件是否存在
R_OK:检查读权限是否存在
W_OK:检查写权限是否存在
X_OK:检查执行权限是否存在

返回值:

  • 如果路径名指定的文件或目录具有所需的权限,则返回0。

  • 如果权限不足,则返回-1,并且errno设置为适当的错误码

 2.4 exit 函数

exit函数是一个用于终止程序运行的函数。当调用exit函数时,程序将立即退出并返回到操作系统。

 2.5 strtok 函数

char *strtok(char *str, const char *delim);

 其中str是要进行分割的字符串,delim是作为分隔符的字符串。函数返回一个指向被分割出的子字符串的指针。

strtok函数陷阱:会改变指针指向的字符串,所以想保留原来str需要用strcpy复制出来处理。

token = strtok(str, ",");
while (token != NULL) {printf("%s\n", token);token = strtok(NULL, ",");
}return 0;

执行上述代码会输出以下结果:

Hello

World

This

is

Strtok

2.6 chdir函数

更改当前工作目录

int chdir(const char *path);

参 数:Path 目标目录,可以是绝对目录或相对目录。

返回值:成功返回0 ,失败返回-1

3.项目代码

3.1服务器代码

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include "config.h" 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>struct Msg msg;
int ss_fd;void handler_cmd(char *cmd){int cmd_int,fd;char *p;FILE *file;char *cmd_pre=cmd;//handle the cmd to numberif(!strcmp(cmd_pre,"ls")) cmd_int=ls;if(!strcmp(cmd_pre,"pwd")) cmd_int=pwd;  if(!strcmp(cmd_pre,"quit")) cmd_int=quit;if(!strcmp(cmd,"lls"))      cmd_int=lls;if(strstr(cmd,"lcd")!=NULL) cmd_int=lcd;if(strstr(cmd_pre,"cd")!=NULL) cmd_int=cd;if(strstr(cmd_pre,"put")!=NULL) cmd_int=put;if(strstr(cmd_pre,"get")!=NULL) cmd_int=get;//handle cmd switch(cmd_int){case ls:case pwd:file=popen(cmd,"r");fread(msg.data,sizeof(msg.data),1,file);printf("%s",msg.data);write(ss_fd,&msg,sizeof(msg));break;case cd:p=strtok(cmd," ");p=strtok(NULL," ");printf("dir:%s \r\n",p);strcpy(msg.data,"change dir over \r\n");write(ss_fd,&msg,sizeof(msg));   //must give a msg backchdir(p);break;case get:p=strtok(cmd," ");p=strtok(NULL," ");printf("dir:%s \r\n",p);	if(!access(p,F_OK)){  //if have this filemsg.flag=dofile;fd=open(p,O_RDONLY);read(fd,&msg.data,sizeof(msg.data));send(ss_fd,&msg,sizeof(msg),0);close(fd);}else{   //if no this filesend(ss_fd,"no this file \r\n",16,0);}break;case put:p=strtok(cmd," ");p=strtok(NULL," ");printf("dir:%s \r\n",p);fd=open(p,O_RDWR|O_CREAT,0666);write(fd,&msg.data,strlen(msg.data));close(fd);strcpy(msg.data,"i have got a file.\r\n");write(ss_fd,&msg,sizeof(msg));   //must give a msg backbreak;case quit:msg.flag=quit;printf("quit==========\r\n");exit(-1);}}int main(void)
{int s_fd,nread,len;struct sockaddr_in s_ddr;  //build server msgstruct sockaddr_in c_ddr;  //save clinet msgs_fd= socket(AF_INET, SOCK_STREAM, 0);//1.build a soket specifiedif(s_fd==-1){perror("error is");}//2.build all binds_ddr.sin_family=AF_INET;s_ddr.sin_port=htons(8880);s_ddr.sin_addr.s_addr=htonl(INADDR_ANY);//give the bindbind(s_fd,(struct sockaddr *)&s_ddr,sizeof(s_ddr));//3.waite for clientlisten(s_fd,8);//4.accept come and connect for oncelen=sizeof(c_ddr);while(1){ss_fd=accept(s_fd,(struct sockaddr *)&c_ddr,&len);if(ss_fd == -1){perror("accept:");}printf("conect succese!==========\r\n");//5.read from connect ss_fdif(fork()==0){   //creat kid pid for handler msg and cmd //5.2 read	while(1){memset(&msg,'\0',sizeof(msg));   //clear msgprintf("====================\r\n");nread=read(ss_fd,&msg,sizeof(msg));if(nread==0){                 // cannot recv cmd printf("connect is cutdon! \r\n");break;}else{                        //can recive cmd printf("server  receved  cmd:%s \r\n",msg.cmd); printf("====================\r\n");handler_cmd(msg.cmd);    //hander the cmd  give msg data		}}}}close(ss_fd);close(s_fd);return 0;
}

3.2客户端代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "config.h" 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int cmd_to_number(char *cmd)
{if(!strcmp(cmd,"ls")) return ls;if(!strcmp(cmd,"pwd")) return pwd;  if(!strcmp(cmd,"quit")) return quit;if(!strcmp(cmd,"lls")) return lls;if(strstr(cmd,"lcd")!=NULL) return lcd;if(strstr(cmd,"cd")!=NULL) return cd;if(strstr(cmd,"put")!=NULL) return put;if(strstr(cmd,"get")!=NULL) return get;return -1;}int handler_cmd(struct Msg msg, int s_fd)
{//handle cmd int fd,n_read; char p_pre[12];char *p=NULL;int ret=cmd_to_number(msg.cmd);switch(ret){case ls:case pwd:case cd:send(s_fd,&msg,sizeof(msg),0);break;case get:send(s_fd,&msg,sizeof(msg),0);break;case put:strcpy(p_pre,msg.cmd);printf("dir:%s \r\n",p_pre);p=strtok(p_pre," ");p=strtok(NULL," ");   //get file_name	printf("dir:%s \r\n",p);if(!access(p,F_OK)){  //if have this filefd=open(p,O_RDONLY);n_read=read(fd,&msg.data,1024);if(n_read>=1024){printf("file over 1024! faild! \r\n");} send(s_fd,&msg,sizeof(msg),0);memset(&msg.data,0,1024);printf("client put cmd is: %s \r\n",msg.cmd);close(fd);}else{   //if no this filesend(s_fd,"no this file",16,0);}break;			case lls:system("ls");break;case lcd:strcpy(p_pre,msg.cmd);p=strtok(p_pre," ");p=strtok(NULL," ");   //get file_printf("dir:%s \r\n",p);chdir(p);break;case quit:send(s_fd,&msg,sizeof(msg),0);close(s_fd); exit(-1);}return ret;
}  void handle_server_msg(struct Msg msg,int s_fd)
{int n_read,fd;char *p;struct Msg recv_msg; //this is new msg   use it becase need pre msg cmdn_read=read(s_fd,&recv_msg,sizeof(recv_msg));  //while blockif(n_read==0){printf("\r\n server is outline! ");exit(-1);}if(recv_msg.flag == dofile){p=strtok(msg.cmd," ");p=strtok(NULL," ");   //get file_name	fd=open(p,O_RDWR|O_CREAT,0666);printf("creat the file\r\n");write(fd,&recv_msg.data,strlen(recv_msg.data));close(fd);putchar('>');fflush(stdout);}else{           //normal direct cmdprintf("-------------------->\r\n");printf("%s >",recv_msg.data);printf("--------------------");putchar('>');fflush(stdout);}}int main(int argc,char *argv[])
{int flag,s_fd,n_read,ret;struct sockaddr_in c_ddr;struct Msg msg;//1.build sockets_fd=socket(AF_INET,SOCK_STREAM,0);//2.0 prepare server addrmemset(&c_ddr,0,sizeof(c_ddr)); //clear c_ddrc_ddr.sin_family=AF_INET;c_ddr.sin_port=htons(8880);inet_aton("127.0.0.1",&c_ddr.sin_addr);//2.connect server get s_fdif(connect(s_fd,(struct sockaddr *)&c_ddr,sizeof(c_ddr))==-1){perror("error");exit(-1);}printf("connect success==============\r\n");while(1){//1.get cmd form keyborad    and  handle cmd to servermemset(&msg,0,sizeof(msg));printf("\r\n >");gets(msg.cmd);int ret=handler_cmd(msg,s_fd);//2.handle the msg form serverif(ret==-1){printf("no this cmd!\r\n ");fflush(stdout);continue;}if(ret==5 || ret==6){printf("client cmd!\r\n ");fflush(stdout);continue;}	handle_server_msg(msg,s_fd);}close(s_fd);return 0;
} 

4.问题总结

  • 在put 发送文件中,当文件大小超过给定字节就会溢出,导致整个结构体崩坏,破坏cmd。
    思考:除了加大给定字节大小,还有其它办法吗?strcpy是怎么实现的
    read函数陷阱:read函数读的字节小于fd文件字节,会崩坏buf里的数据。
  • strtok函数会破坏使用的字符串,要保留原来字符串需要strcpy复制出来处理。
  • 本地命令不用服务器处理的命令,ret=5,ret=6不要进入hanle_server_msg用recv函数阻塞

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

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

相关文章

ELK原理和介绍

为什么用到ELK&#xff1a; 一般我们需要进行日志分析场景&#xff1a;直接在日志文件中 grep、awk 就可以获得自己想要的信息。但在规模较大的场景中&#xff0c;此方法效率低下&#xff0c;面临问题包括日志量太大如何归档、文本搜索太慢怎么办、如何多维度查询。需要集中化…

java-参数传递机制

java参数传递机制都是值传递。 基本类型参数传输都是数据值。 传递到方法中的值是拷贝后的值。 引用类型参数传输的都是地址值。 如果是数组的参数传递&#xff0c;那么是引用传递&#xff08;本质上还是值传递&#xff0c;但是由于数组的值传递是传递数组的内存地址&#xf…

Llama模型结构解析(源码阅读)

目录 1. LlamaModel整体结构流程图2. LlamaRMSNorm3. LlamaMLP4. LlamaRotaryEmbedding 参考资料&#xff1a; https://zhuanlan.zhihu.com/p/636784644 https://spaces.ac.cn/archives/8265 ——《Transformer升级之路&#xff1a;2、博采众长的旋转式位置编码》 前言&#x…

SpringCloud(十)——ElasticSearch简单了解(二)DSL查询语句及RestClient查询文档

文章目录 1. DSL查询文档1.1 DSL查询分类1.2 全文检索查询1.3 精确查询1.4 地理查询1.5 查询算分1.6 布尔查询1.7 结果排序1.8 分页查询1.9 高亮显示 2. RestClient查询文档2.1 查询全部2.2 其他查询语句2.3 排序和分页2.4 高亮显示 1. DSL查询文档 1.1 DSL查询分类 查询所有…

使用Windbg动态调试排查软件启动不了的问题

目录 1、问题说明 2、初步分析 3、使用Windbg启动程序进行动态调试 4、进一步分析 5、何时使用Windbg静态分析&#xff1f;何时使用Windbg进行动态调试&#xff1f; 6、最后 VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&…

14:00面试,14:08就出来了,问的问题有点变态

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%,…

Kubernetes可视化管理工具Kuboard部署使用及k8s常用命令梳理记录

温故知新 &#x1f4da;第一章 前言&#x1f4d7;背景&#x1f4d7;目的&#x1f4d7;总体方向 &#x1f4da;第二章 安装 Kubernetes 多集群管理工具 - Kuboard v3&#x1f4d7;部署方式&#x1f4d7;通过Kuboard v3 - Kubernetes安装&#xff08;在master节点执行)&#x1f4…

SpringBoot复习:(60)文件上传的自动配置类MultipartAutoConfiguration

可以看到&#xff0c;定义了一个类型为StandartServletMultipartResolver的bean 用来进行文件上传&#xff0c;定义了一个类型为MultipartConfigElement的bean用来进行上传相关的配置&#xff0c;其中使用了MultipartProperties中的属性&#xff0c;这个类的定义如下&#xff1…

vue+element-ui el-table组件二次封装实现虚拟滚动,解决数据量大渲染DOM过多而卡顿问题

一、此功能已集成到TTable组件中 二、最终效果 三、需求 某些页面不做分页时&#xff0c;当数据过多&#xff0c;会导致页面卡顿&#xff0c;甚至卡死 四、虚拟滚动 一、固定一个可视区域的大小并且其大小是不变的&#xff0c;那么要做到性能最大化就需要尽量少地渲染 DOM 元素…

梯度下降算法入门

提到梯度下降我们知道梯度下降算法是很多机器学习算法、深度学习算法的基础。 首先我们需要明确一些概念什么是梯度&#xff1a; 梯度的本意是一个向量&#xff08;矢量&#xff09;&#xff0c;表示某一函数在该点处的方向导数沿着该方向取得最大值&#xff0c;即函数在该点处…

软件测试/测试开发丨Python 内置库 正则表达式

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27058 python 内置库 正则表达式 目录 正则表达式使用re模块实现正则表达式操作 正则表达式 正则表达式就是记录文本规则的代码可以查找操作符合某些复…

HBuilderX修改manifest.json设置,解决跨域问题(CORS、Cross-Origin)

搭建一个前台uniapp&#xff0c;后台springboot的开发环境时&#xff0c;遇到了跨域问题。 console提示错误信息&#xff1a; Access to XMLHttpRequest at http://10.0.180.203/api/cms/getAdList?apId1 from origin http://localhost:8080 has been blocked by CORS policy…