LinuxFTP云盘-文件服务系统

news2024/11/19 19:26:14

目录

1.项目介绍

2.项目运行展示

3.实现思路

服务端:

客户端:

4.相关调用函数

socket():创建一个网络通信端点原型:int socket(int domain, int type, int protocol);

atoi():将字符串转变成整型数据原型:int atoi(const char *nptr);

 htons():将16位无符号数从主机字节序转换成网络字节序原型:uint16_t htons(uint16_t hostshort);

 inet_aton():将IP地址从字符串类型转换成网络字节序原型:int inet_aton(const char *cp, struct in_addr *inp);

 inet_ntoa():将IP地址从网络字节序转换成字符串类型原型:char *inet_ntoa(struct in_addr in);

 bind():为套接字添加信息(协议族、IP地址、端口号)原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

 listen():监听客户端的连接原型:int listen(int sockfd, int backlog);

 accept():等待客户端的连接,当没有客户端连接时,accept()会阻塞等待原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

 connect():客户端连接服务器原型:int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

 fork():创建一个子进程原型:pid_t fork(void)

 open():打开一个文件原型:int open(const char *pathname, int flags, mode_t mode);

 read():从某个文件中读取数据,没读到数据时会阻塞等待原型:int read(int fd, void *buf, size_t count);

 write():向某个文件写入数据原型:int write(int fd, const void *buf, size_t count);

 lseek():移动文件的光标,通常用lseek(fd,0,SEEK_END)获取文件长度原型:int lseek(int fd, off_t offset, int whence);

 close(),一般不用主动关闭文件,在进程终止时,内核自动关闭该进程打开的文件原型:int close(int fd)

 strtok():字符串分割函数原型:char *strtok(char *str, const char *delim);

strcmp():字符串比较函数原型:int strcmp(const char *s1, const char *s2);

strstr():字符串包含函数原型:char *strstr(const char *s1, const char *s2);

 strcat():字符串拼接函数原型:char *strcat(char *str1, const char *str2);

 strcpy():字符串复制函数原型:char *strcpy(char *str1, const char *str2)

 memset():将一块内存设定成指定的值原型:void *memset(void *s, int c, size_t n);

 system():执行某个命令,命令执行后继续从调用点执行程序原型:int system(const char *command);

 popen():执行某个命令,并将执行命令后得到的数据存放到一个文件流中原型:FILE *popen(const char *command, const char *type);

 fread():从某个文件流中读取数据原型:int fread(void *ptr, size_t size, size_t nmemb,FILE *stream);

 fflush():刷新缓冲区,将某个流未写的数据传送至内核原型:int fflush(FILE *stream);

 chdir():修改当前的工作目录原型:int chdir(const char *path);

 access():查看文件是否具有某个权限原型: int access(const char * pathname,int mode);

5.完整代码示例和解析

服务端代码:

客户端代码:


1.项目介绍

在 Linux 环境下使用文件、线程、网络编程等相关操作,实现 ls、lls、cd、lcd、put、get、pwd、lpwd 功能。 树莓派 3B 作为服务端、Ubuntu 作为客户端,允许 Ubuntu 上多个进程作客户端连接服务端。客户端使用 lls、 lcd、lpwd 命令查看客户端目录文件、切换工作目录、查看当前目录;使用 ls、cd、pwd 命令查看服务端目录文件、切换工作目录、查看当前目录;使用 put 加文件名将客户端文件上传至服务端,使用 get 加文件名从 服务端将文件下载至客户端,实现在同一局域网下树莓派 3B 和 Ubuntu 之间文件的

2.项目运行展示

3.实现思路

服务端:
  • 与客户端建立socket连接
  • 读取客户端发送的命令
  • 进行相关的命令识别和处理,将执行命令所获得的数据发送给客户端。
客户端:
  • 与服务器建立socket连接
  • 获取用户输入的命令,进行相关的命令识别和处理
  • 客户端会进行系统调用执行带l前缀命令,不带l前缀的命令将会发送给服务器
  • 对服务器发送的数据进行处理

4.相关调用函数

socket():创建一个网络通信端点
原型:int socket(int domain, int type, int protocol);

返回值:调用成功返回套接字描述符,调用失败返回-1

参数: 

int domain:指明所使用的协议族,通常为 AF_INET,表示互联网协议族(TCP/IP 协议族)

  • AF_INET IPv4因特网域.
  • AF_INET6 IPv6 因特网域
  • AF_UNIX Unix 域
  • AF_ROUTE 路由套接字
  • AF_KEY 密钥套接字
  • AF_UNSPEC 未指定

int type:选择套接字的类型,在这里我们用SOCK_STREAM

  • SOCK_STREAM:
  • 流式套接字提供可靠的、面向连接的通信流,它使用 TCP 协议,从而保证了数据传输的正确性和顺序性
  • SOCK_DGRAM:
  • 数据报套接字定义了一种无连接的服,数据通过相互独立的报文进行传输,是无序的,并且不保证是可靠、无差错的。它使用教据报协议UDP
  • SOCK_RAW:                                                                                                                            允许程序使用低层协议,原始套接字允许对底层协议如 IP 或 ICMP 进行直接访问,功能强大但使用较为不便,主要用于一些协议的开发

int protocol:选择协议,通常为0, 表示type参数对应的默认协议

  • IPPROTO_TCP TCP 传输协议
  • IPPROTO_UDP UDP 传输协议
  • IPPROTO_SCTP SCTP 传输协议
  • IPPROTO_TIPC TIPC 传输协议
atoi():将字符串转变成整型数据
原型:int atoi(const char *nptr);

返回值:返回转换之后得到的int型数据

参数:

  • const char *nptr:需要进行转换的字符串
 
htons():将16位无符号数从主机字节序转换成网络字节序
原型:uint16_t htons(uint16_t hostshort);

返回值:转换之后的TCP/IP网络字节序

参数:

  • uint16_t hostshort:16位无符号整数
 
inet_aton():将IP地址从字符串类型转换成网络字节序
原型:int inet_aton(const char *cp, struct in_addr *inp);

返回值:调用成功返回非0,调用失败返回0

参数:

  • const char *cp:字符串类型的IP地址
  • struct in_addr *inp:sockaddr_in类型结构体里的in_addr类型结构体地址

 
inet_ntoa():将IP地址从网络字节序转换成字符串类型
原型:char *inet_ntoa(struct in_addr in);

返回值:指向字符串类型IP地址的字符串指针

参数:

  • struct in_addr in:sockaddr_in类型结构体里的in_addr类型结构体

 
bind():为套接字添加信息(协议族、IP地址、端口号)
原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

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

参数:

  • int sockfd:套接字描述符
  • const struct sockaddr *addr:sockaddr类型结构体地址,在IPv4因特网域中,存储套接字信息用sockaddr_in类型结构体,因此在传入bind()参数时要对该结构体进行强制转换
  • socklen_t addrlen:参数二的内存空间大小 
 
listen():监听客户端的连接
原型:int listen(int sockfd, int backlog);

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

参数:

  • int sockfd:套接字描述符
  • int backlog:指定在请求队列中允许的最大连接数
 
accept():等待客户端的连接,当没有客户端连接时,accept()会阻塞等待
原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

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

参数:

  • int sockfd:套接字描述符
  • const struct sockaddr *addr:sockaddr类型结构体地址
  • socklen_t *addrlen:参数二内存空间大小的值的地址
     
 
connect():客户端连接服务器
原型:int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

返回值:调用成功返回套接字描述符,调用失败返回-1

参数:

  • int sockfd:套接字描述符
  • const struct sockaddr *addr:sockaddr类型结构体地址,在IPv4因特网域中,存储套接字信息用sockaddr_in类型结构体,因此在传入bind()参数时要对该结构体进行强制转换
  • socklen_t *addrlen:参数二内存空间大小
 
fork():创建一个子进程
原型:pid_t fork(void)

返回值:调用成功返回两次,0或非负整数,调用失败返回-1

  • 0:子进程
  • 非负整数(子进程的pid):父进程
 
open():打开一个文件
原型:int open(const char *pathname, int flags, mode_t mode);

返回值:调用成功返回一个文件描述符,调用失败返回-1

参数:

  • const char *pathname:文件名(相对路径)
  • int flags:打开文件的方式及附带操作
  • mode_t mode:(可选参数)文件访问的权限
 
read():从某个文件中读取数据,没读到数据时会阻塞等待
原型:int read(int fd, void *buf, size_t count);

返回值:读入成功时,返回读取的字节数(如果读文件开始前光标到达文件尾端则返回0)读入失败时,返回-1

参数:

  • fd:文件描述符
  • void *buf:读取的数据存放位置
  • size_t count:读取的字节数
 
write():向某个文件写入数据
原型:int write(int fd, const void *buf, size_t count);

返回值:写入成功时,返回写入的字节数,写入数据为空返回0,写入失败返回-1

参数:

  • fd:文件描述符
  • void *buf:写入文件的数据
  • size_t count:写入文件的字节数
 
lseek():移动文件的光标,通常用lseek(fd,0,SEEK_END)获取文件长度
原型:int lseek(int fd, off_t offset, int whence);

返回值:调用成功返回光标偏移字节,调用失败返回-1

参数:

  • fd:文件描述符
  • off_t offset:偏移字节,0为不偏移,-a为往前偏移a个字节,b为往前偏移b个字节
  • int whence:光标位置
     
 
close(),一般不用主动关闭文件,在进程终止时,内核自动关闭该进程打开的文件
原型:int close(int fd)

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

参数:

  • fd:文件描述符
 
strtok():字符串分割函数
原型:char *strtok(char *str, const char *delim);

返回值:

  • 第一次传入字符串和分隔符时,返回分割的字符串
  • 第二次传入NULL和分隔符时,返回分隔的字符串
  • 直到最后一次传入NULL和空字符串时,返回最后一个分割的字符串
  • 其中第一次字符串被分割后,值和大小为第一次分割出来的字符串

参数:

  • char *str:字符串
  • const char *delim:分隔符
strcmp():字符串比较函数
原型:int strcmp(const char *s1, const char *s2);

返回值:如果两个字符串相等返回0,两个字符串不相等返回其他值

参数:

  • const char *s1:字符串1
  • const char *s2:字符串2
strstr():字符串包含函数
原型:char *strstr(const char *s1, const char *s2);

返回值:如果字符串s1包含字符串s2,返回包含字符及后面字符,如果字符串s1不包含字符串s2则返回NULL

参数:

  • const char *s1:字符串1
  • const char *s2:字符串2
 
strcat():字符串拼接函数
原型:char *strcat(char *str1, const char *str2);

返回值:返回指向字符串2拼接到字符串1的字符串地址的指针

参数:

  • const char *s1:字符串1
  • const char *s2:字符串2
 
strcpy():字符串复制函数
原型:char *strcpy(char *str1, const char *str2)

返回值:返回指向字符串2复制到字符串1尾端的字符串地址的指针

参数:

  • const char *s1:字符串1
  • const char *s2:字符串2
 
memset():将一块内存设定成指定的值
原型:void *memset(void *s, int c, size_t n);

返回值:返回一个指向内存s的指针

参数:

  • void *s:内存块
  • int c:指定值
  • size_t n:要被设置该值的字符数
 
system():执行某个命令,命令执行后继续从调用点执行程序
原型:int system(const char *command);

返回值:

  • 调用/bin/sh失败时返回127,其他失败原因返回-1
  • const char *command参数为NULL时返回非0值
  • 调用成功返回执行shell命令后的返回值

参数:

  • const char *command:命令
 
popen():执行某个命令,并将执行命令后得到的数据存放到一个文件流中
原型:FILE *popen(const char *command, const char *type);

返回值:调用成功返回文件流,调用失败返回NULL

参数:

  • const char *command:命令
  • const char *type:返回的文件流权限,w:文件流可写,r: 文件流可读(与system等价)
 
fread():从某个文件流中读取数据
原型:int fread(void *ptr, size_t size, size_t nmemb,FILE *stream);

返回值:读入成功时,返回读取的字节数,读入失败时,返回-1

参数:

  • const void *ptr:读取数据存放位置
  • size_t size:每次读的字节数
  • size_t nmemb:读的次数
  • FILE *stream:文件流
 
fflush():刷新缓冲区,将某个流未写的数据传送至内核
原型:int fflush(FILE *stream);

返回值:调用成功返回0,调用失败返回EOF

参数:

  • FILE *stream:文件流
  • fflush(stdin):刷新标准输入缓冲区,把输入缓冲区里的东西丢弃
  • fflush(stdout):刷新标准输出缓冲区,把输出缓冲区里的东西强制打印到标准输出设备上
 
chdir():修改当前的工作目录

原型:int chdir(const char *path);

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

参数:

  • const char *path:新的当前工作目录,绝对路径或者相对路径
 
access():查看文件是否具有某个权限

原型: int access(const char * pathname,int mode);

返回值:如果文件具有某种权限返回0,不具有某种权限返回-1

参数:

  • const char *pathname:文件名(相对路径)
  • int mode:权限

5.完整代码示例和解析

服务端代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <linux/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
 
#define LS 1
#define CD 2
#define PWD 3
#define PUT 5
#define GET 15
 
struct Msg 
{
	int type;
	char cmd[50];
	char data[5120];
};
 
int cmd_distinguish(char *cmd)
{
	int ret;
	cmd = strtok(cmd,"\n");	//由于客户端获取用户输入时,会使用enter键,因此传输到服务器的命令都带有换行符,需要进行命令分割
	if(!strcmp("ls",cmd)){
		ret = LS;
	}else if(strstr(cmd,"cd") != NULL){
		ret = CD;
	}else if(strstr(cmd,"get") != NULL){
		ret = GET;
	}else if(strstr(cmd,"put") != NULL){
		ret = PUT;
	}else if(!strcmp("pwd",cmd)){
		ret = PWD;
	}else{
		ret = 0;
	}
	return ret;
}
 
//将带有文件名、路径名的命令进行处理分割
//如命令“get 1.c”,该函数就会返回1.c
char *str_decompose(char *cmd)
{
	strtok(cmd," ");
	cmd = strtok(NULL," ");
	return cmd;
}
 
void cmd_handle(int ret,struct Msg msg,int c_fd)
{
	FILE *fp = NULL;
	int n_fread;
	char file_path[20] = "./"; //当前路径
	switch(ret){
		case PWD:
			fp = popen("pwd","r"); //调用终端执行pwd命令,并将数据存放到fp文件流中
			memset(msg.data,0,sizeof(msg.data));
			n_fread = fread(msg.data,1,sizeof(msg.data),fp);//读取文件流的数据
			msg.type = 0;
			write(c_fd,&msg,sizeof(msg)); //向客户端发送数据
			fflush(stdout); //刷新标准输出缓冲区,把输出缓冲区里的东西强制打印到标准输出设备上
			break;
		case LS:
			fp = popen("ls","r");
			memset(msg.data,0,sizeof(msg.data));
			n_fread = fread(msg.data,1,sizeof(msg.data),fp);
			msg.type = 0;
			write(c_fd,&msg,sizeof(msg));
			fflush(stdout);
			break;
		case CD:
			if(chdir(str_decompose(msg.cmd)) <0){ //修改当前工作目录

				perror("chdir");
			}
			break;
		case GET:
			strcat(file_path,str_decompose(msg.cmd));
			if(access(file_path,F_OK) < 0){ //判断服务器是否拥有客户端想要获取的文件
				perror("access");
				memset(msg.data,0,sizeof(msg.data));
				msg.type = 0;
				strcpy(msg.data,"Target file does not exist");
				write(c_fd,&msg,sizeof(msg));
			}else if(access(file_path,R_OK) < 0){ //判断服务器是否对该文件有读权限
				memset(msg.data,0,sizeof(msg.data));
				msg.type = 0;
				strcpy(msg.data,"The target file does not have read permission");
				write(c_fd,&msg,sizeof(msg));
			}else{ //获取该文件的内容,发送给客户端
				int file_fd = open(file_path,O_RDONLY,0600);
				if(file_fd < 0){
					perror("open");
				}
				int file_size = lseek(file_fd,0,SEEK_END);
				if(file_size < 0){
					perror("lseek");
				}
				lseek(file_fd,0,SEEK_SET);
				memset(msg.data,0,sizeof(msg.data));
				msg.type = GET;
				if(read(file_fd,msg.data,file_size) < 0){
					perror("read");
				}
				close(file_fd);
				write(c_fd,&msg,sizeof(msg));
			}
			break;
		case PUT:
			strcat(file_path,str_decompose(msg.cmd));
			int file_fd = open(file_path,O_RDWR|O_CREAT,0666); //创建一个文件,写入客户端想要存放的文件的数据
			if(file_fd < 0){
				perror("open");
			}
			if(write(file_fd,msg.data,strlen(msg.data)) < 0){
				perror("write");
			}
			close(file_fd);
			break;
	}
}
 
 
 
int main(int argc,char **argv)
{
 
	struct sockaddr_in so_addr;
	struct sockaddr_in cl_addr;
 
	if(argc != 3){
		printf("Insufficient or inconsistent parameters\n");
		exit(-1);
	}
 
	memset(&so_addr,0,sizeof(struct sockaddr_in));
	memset(&cl_addr,0,sizeof(struct sockaddr_in));
 
	//1.socket
	int s_fd = socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == -1){
		printf("socket is failusr\n");
		perror("socket");
		exit(-1);
	}
 
	so_addr.sin_family = AF_INET;
	so_addr.sin_port = htons(atoi(argv[2])); //将端口号转化成网络字节序
	inet_aton(argv[1],&so_addr.sin_addr); //将IP地址转化为网络字节序
 
	//2.bind
	int bd = bind(s_fd,(struct sockaddr *)&so_addr,sizeof(struct sockaddr_in));
	if(bd == -1){
		printf("bind is failusr\n");
		perror("bind");
		exit(-1);
	}
 
	//3.listen
	int ln = listen(s_fd,10);
	if(ln == -1){
		printf("listen is failusr\n");
		perror("listen");
		exit(-1);
	}
 
	int c_fd;
	int mark = 0;
	int clean = sizeof(struct sockaddr_in);
	pid_t pid;
	while(1){
	//4.accept
		c_fd = accept(s_fd,(struct sockaddr *)&cl_addr,&clean);
		if(c_fd == -1){
			printf("accept is failusr\n");
			perror("accept:");
			exit(-1);
		}
		mark++;
		printf("get No.%d connect: %s\n",mark,inet_ntoa(cl_addr.sin_addr));
	
	//连接成功后创建子进程接受客户端命令
		pid = fork();
		if(pid < 0){		
			perror("fork");
			exit(-1);
		}
		else if(pid == 0){
			char *fp = NULL;
			struct Msg msg;
			int ret = 0;
			int c_read;
			while(1){
				memset(msg.cmd,0,sizeof(msg.cmd));
				c_read = read(c_fd,&msg,sizeof(msg)); //读取客户端发送的命令
				if(c_read <= 0){
					perror("read");
					break;
				}else{
					printf("get size is %d's cmd from NO.%d client:%s\n",c_read,mark,msg.cmd);
					ret = cmd_distinguish(msg.cmd); //对客户端传送的命令进行识别
					cmd_handle(ret,msg,c_fd); //对相关命令进行处理
 
				}
 
			}
		}
		close(c_fd);
	}
	close(s_fd);
	
	return 0;
}
客户端代码:
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
 
struct Msg
{
	int type;
	char cmd[50];
	char data[5120];
};
 
#define LLS 1
#define LCD 2
#define LPWD 3
#define CD 4
#define LQUIT 7
#define PUT 8
#define CMD 9
#define QUIT 12
#define LS 13
#define PWD 14
#define GET 15
 
 
int cmd_distinguish(char *cmd)
{
	int ret;
	cmd = strtok(cmd,"\n");
	if(!strcmp("lls",cmd)){
		ret = LLS;
	}else if(strstr(cmd,"lcd") != NULL){
		ret = LCD;
	}else if(!strcmp("lpwd",cmd)){
		ret = LPWD;
	}else if(!strcmp("ls",cmd)){
		ret = LS;
	}else if(!strcmp("lquit",cmd)){
		ret = LQUIT;
	}else if(strstr(cmd,"cd") != NULL){
		ret = CD;
	}else if(strstr(cmd,"get") != NULL){
		ret = GET;
	}else if(strstr(cmd,"put") != NULL){
		ret = PUT;
	}else if(!strcmp("pwd",cmd)){
		ret = PWD;
	}else{
		ret = 0;
	}
	return ret;
}
 
 
char *str_decompose(char *cmd)
{
	strtok(cmd," ");
	cmd = strtok(NULL," ");
	return cmd;
}
 
 
int cmd_handle(int ret,struct Msg msg,int c_fd)
{
 
	FILE *fp = NULL;
	int n_fread;
	char file_path[20] = "./";
	char tmp_cmd[50];
	switch(ret){
		case LPWD:
			printf("--------------------------------------\n");
			printf("\n");
			system("pwd"); //调用终端执行pwd命令,并将数据输出到标准输出上
			printf("\n");
			printf("--------------------------------------\n");
			printf("\n");
			break;
		case LLS:
			printf("--------------------------------------\n");
			printf("\n");
			system("ls"); //调用终端执行ls命令,并将数据输出到标准输出上
			printf("\n");
			printf("--------------------------------------\n");
			printf("\n");
			break;
		case LCD:
			if(chdir(str_decompose(msg.cmd)) < 0){//修改当前工作目录
				perror("chdir");
			}                       
			printf("\n");
			break;
		case LQUIT:
			printf("--------------------------------------\n");
			printf("\n");
			printf("client is quit\n");
			printf("\n");
			printf("--------------------------------------\n");
			printf("\n");
			exit(0);//退出当前进程
			break;
		case LS:	
			msg.type = 0;	
			write(c_fd,&msg,sizeof(msg)); //将用户输入发送给服务器,让服务器根据命令进行相应的行为
			break;
		case PWD:
			msg.type = 0;	
			write(c_fd,&msg,sizeof(msg)); //将用户输入发送给服务器,让服务器根据命令进行相应的行为
			break;
		case CD:
			msg.type = 0;	
			write(c_fd,&msg,sizeof(msg)); //将用户输入发送给服务器,让服务器根据命令进行相应的行为
			break;
		case GET:
			msg.type = 0;	
			write(c_fd,&msg,sizeof(msg)); //将用户输入发送给服务器,让服务器根据命令进行相应的行为
			break;
		case PUT:
			memset(tmp_cmd,0,sizeof(tmp_cmd));
			strcpy(tmp_cmd,msg.cmd); //put 1.c ->tmp.cmd
			strcat(file_path,str_decompose(msg.cmd)); // ./1.c->file_path
			memset(msg.cmd,0,sizeof(msg.cmd));
			strcpy(msg.cmd,tmp_cmd);
			if(access(file_path,F_OK) < 0){ //判断客户端是否拥有想要存放到服务器的文件
				printf("--------------------------------------\n");
				printf("\n");
				printf("Target file does not exist\n");
				printf("\n");
				printf("--------------------------------------\n");
				printf("\n");
 
			}else if(access(file_path,R_OK) < 0){ //判断客户端是否对该文件有读权限
				printf("--------------------------------------\n");
				printf("\n");
				printf("The target file does not have read permission\n");   	
				printf("\n");
				printf("--------------------------------------\n");
				printf("\n");
			}else{ //获取该文件的内容,发送给服务器
				int pfile_fd = open(file_path,O_RDONLY,0666);
				if(pfile_fd < 0){
					perror("open");
				}
				int file_size = lseek(pfile_fd,0,SEEK_END);
				if(file_size < 0){
					perror("lseek");
				}
				lseek(pfile_fd,0,SEEK_SET);
				memset(msg.data,0,sizeof(msg.data));
				if(read(pfile_fd,msg.data,file_size) < 0){
					perror("read");
				}
				close(pfile_fd);
				write(c_fd,&msg,sizeof(msg));
				printf("--------------------------------------\n");
				printf("\n");
				printf("Target file is on server\n");   	
				printf("\n");
				printf("--------------------------------------\n");
				printf("\n");
			}
			break;
		default:
			printf("--------------------------------------\n");
			printf("\n");
			printf("Input error, please re-enter\n");   	
			printf("\n");
			printf("--------------------------------------\n");
			printf("\n");
			break;
 
	}
	return ret;
}
 
//对服务器发送的数据进行处理
void from_socket_data_handle(struct Msg msg,int c_fd)
{
	struct Msg socket_msg;
	int n_read;
	int file_fd;
	char file_path[20] = "./";
 
	n_read = read(c_fd,&socket_msg,sizeof(socket_msg));
	if(n_read == -1){
		perror("read socket");
		exit(-1);
	}else if(socket_msg.type == GET){ //如果是GET指令返回的数据,就存进文件中
		strcat(file_path,str_decompose(msg.cmd));
		file_fd = open(file_path,O_RDWR|O_CREAT,0666);
		write(file_fd,socket_msg.data,strlen(socket_msg.data));
		fflush(stdout);
		close(file_fd);
		printf("--------------------------------------\n");
		printf("\n");
		printf("%s\n","Get target file from server\n");
		printf("--------------------------------------\n");
		printf("\n");
	}else{ //如果是其他数据就直接打印出来
		printf("--------------------------------------\n");
		printf("\n");
		printf("%s\n",socket_msg.data);
		printf("\n");
		printf("--------------------------------------\n");
		printf("\n");
	}
 
}
 
int main(int argc,char **argv)
{
	struct sockaddr_in c_addr;
	memset(&c_addr,0,sizeof(struct sockaddr_in));
 
	//1.socket
	int c_fd = socket(AF_INET,SOCK_STREAM,0);
	if(c_fd == -1){
		printf("socket is failusr\n");
		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); //将IP地址转化为网络字节序
 
	//2.connect
	if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1){
		perror("connect");
		exit(-1);
	}
 
	int n_read;
	struct Msg msg;
	int ret = 0;
	int mark = 0;
	int tmp = 0;
	while(1){
		memset(msg.cmd,0,sizeof(msg.cmd));
		memset(msg.data,0,sizeof(msg.data));
 
		fgets(msg.cmd,sizeof(msg.cmd),stdin); //获取用户输入的命令
		ret = cmd_distinguish(msg.cmd); //对用户键入的命令进行识别
		tmp = cmd_handle(ret,msg,c_fd); //对命令进行处理
		if(tmp > CMD){
			from_socket_data_handle(msg,c_fd); //对服务器传送的数据进行处理
		}
 
		fflush(stdout);
 
	}	
	close(c_fd);
	return 0;
}

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

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

相关文章

【C刷题】day2

一、选择题 1、以下程序段的输出结果是&#xff08; &#xff09; #include<stdio.h> int main() { char s[] "\\123456\123456\t"; printf("%d\n", strlen(s)); return 0; } A: 12 B: 13 C: 16 D: 以上都不对【答案】&#xff1a; A 【解析】…

黑马JVM总结(八)

&#xff08;1&#xff09;StringTable面试题 1.8 1.6时 &#xff08;2&#xff09;StringTable的位置 jvm1.6时StringTable是常量池的一部分&#xff0c;它随着常量池存储在永久代当中&#xff0c;在1.7、1.8中从永久代变成了堆中&#xff0c;为什么做这个更改呢&#xff1f…

c语言每日一练(15)

前言&#xff1a;每日一练系列&#xff0c;每一期都包含5道选择题&#xff0c;2道编程题&#xff0c;博主会尽可能详细地进行讲解&#xff0c;令初学者也能听的清晰。每日一练系列会持续更新&#xff0c;上学期间将看学业情况更新。 五道选择题&#xff1a; 1、程序运行的结果…

家政服务接单小程序开发源码 家政保洁上门服务小程序源码 开源完整版

分享一个家政服务接单小程序开发源码&#xff0c;家政保洁上门服务小程序源码&#xff0c;一整套完整源码开源&#xff0c;可二开&#xff0c;含完整的前端后端和详细的安装部署教程&#xff0c;让你轻松搭建家政类的小程序。家政服务接单小程序开发源码为家政服务行业带来了诸…

【数据在内存中的储存】

1.整数在内存中的存储&#x1f4bb; 在讲解操作符的时候&#xff0c;我们就讲过了下⾯的内容&#xff1a; 整数的2进制表⽰⽅法有三种&#xff0c;即原码、反码和补码 三种表⽰⽅法均有符号位和数值位两部分&#xff0c;符号位都是⽤0表⽰“正”&#xff0c;⽤1表⽰“负”&…

C# Onnx Yolov8 Fire Detect 火焰识别,火灾检测

效果 项目 代码 using Microsoft.ML.OnnxRuntime.Tensors; using Microsoft.ML.OnnxRuntime; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using Syste…

HBS 家庭总线驱动和接收芯片MS1192,应用于电话及相关设备、空调设备、安全设备、AV 装置

MS1192 是适用于 HBS 总线规范&#xff08;日本电子工业协会&#xff09; 的适配器芯片&#xff0c;具备发送、接收数据的功能。在发送接收 单元中&#xff0c;采用 AMI 编码方式&#xff0c;可使用双绞线进行互联&#xff0c;信 号传输采用差分方式。 芯片采用单电源…

竞赛 基于机器视觉的火车票识别系统

文章目录 0 前言1 课题意义课题难点&#xff1a; 2 实现方法2.1 图像预处理2.2 字符分割2.3 字符识别部分实现代码 3 实现效果最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器视觉的火车票识别系统 该项目较为新颖&#xff0c;适合作为竞赛…

【Unity3D】资源管理

1 前言 Unity 中 资源管理方案主要有 Resources、TextAsset、ScriptableObject 、AssetDatabase、PlayerPrefs、Addressables、AssetBundle、SQLite&#xff0c;本文将介绍其中大部分方案。 2 Resources Resources 主要用于加载资源&#xff0c;被加载的资源需要放在 Resource…

微信小程序学习笔记1.0

第1章 微信小程序基础 1.1 微信小程序介绍 1.1.1 什么是微信小程序 微信小程序的特点&#xff1a; ① 微信小程序是不需要下载和安装的&#xff1b; ② 它可以完成App应用软件的交互功能&#xff1b; ③ 用户扫一扫或者搜一下就可以使用小程序&#xff1b; ④ 微信小程序…

什么是气象站?气象站的简介

气象站是一种用于收集、分析和处理气象数据的设备&#xff0c;能够为人们提供及时、准确的气象数据和决策支持。下面是对气象站的详细介绍&#xff1a; 气象站是一种用于气象观测的设备&#xff0c;它通过各种传感器和测量设备&#xff0c;对大气环境中的温度、湿度、气压、风…

“微软爱写作”连词摘录

目录 前言连词1 引入2 承接3 最后4 因果关系5 转折关系6 并列关系7 递进关系8 比较关系&#xff08;相同点&#xff09;9 对照关系&#xff08;不同点&#xff09;10 举例关系11 例外关系12 强调关系13 条件关系14 归纳总结15 方位关系16 目的关系17 重申关系18 时间关系19 结果…

Java面试八股文宝典:初识数据结构-数组的应用扩展之HashMap

前言 除了基本的数组&#xff0c;还有其他高级的数据结构&#xff0c;用于更复杂的数据存储和检索需求。其中&#xff0c;HashMap 是 Java 集合框架中的一部分&#xff0c;用于存储键值对&#xff08;key-value pairs&#xff09;。HashMap 允许我们通过键来快速查找和检索值&…

Java基础入门·File类的使用

前言 ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ File类的创建方法 File类介绍 ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ …

java基础特别问题

基础学习 数据类型转换运算符字符串方法传递参数: 值传递构造器Stringnew关键字创建的对象则按对象方式去处理 静态代码块和实例代码块静态代码块&#xff1a;实例代码块&#xff1a; 多态匿名内部类格式&#xff1a;StringJoiner (JDK1.8)小数计算BigDecimal时间时间集合List …

python: excel假期时间提取统计

# encoding: utf-8 # 版权所有 2023 涂聚文有限公司 # 许可信息查看&#xff1a; # 描述&#xff1a; # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 311 # Datetime : 2023/9/3 7:04 # User : geovindu # Product : PyCharm # Proje…

Java从Tif中抽取最大的那张图进行裁剪成x*y份

之前我有一篇帖子《kfb格式文件转jpg格式》讲述到 kfb > tif > jpg&#xff0c;但是针对于超大tif中的大图是无法顺利提取的&#xff0c;就算是能顺利提取&#xff0c;试想一下&#xff0c;2G的tif文件&#xff0c;如果能提取处理最大的那张图&#xff0c;并且在不压缩的…

Java代码审计16之fastjson反序列化漏洞(1)

文章目录 1、简介fastjson2、fastjson的使用2.1、将类序列化为字符串2.2、将字符串还原为对象2.3、小结以上2.4、稍微扩展思路 3、fastjson漏洞利⽤原理与dnslog4、JdbcRowSetImpl利用链4.1、JdbcRowSetImpl的基本知识4.2、利用代码复现4.3、生成poc4.4、模拟真实场景4.5、利用…

03目标检测-传统方法与深度学习算法对比

目录 一、目标学习的检测方法变迁及对比 二、深度学习目标检测算法基本流程 三、传统目标检测算法VS深度学习目标检测算法 一、目标学习的检测方法变迁及对比 “目标检测“是当前计算机视觉和机器学习领域的研究热点。从Viola-Jones Detector、DPM等冷兵器时代的智…

jq弹窗拖动改变宽高

预览效果 <div classtishiMask><div class"tishiEm"><div id"coor"></div><div class"topNew ismove"><span class"ismove">提示</span><p onclick"closeTishi()"></p&…