Linux阶段性项目——FTP服务器

一、FTP服务概述

​FTP为File Transfer Protocol的缩写,即文件传输协议,是TCP/IP 协议族中的协议之一。FTP是一个用于在计算机网络上在客户端和服务器之间进行文件传输的应用层协议。RFC 959定义了FTP协议规范。是互联网上使用的最广泛的文件传输协议,用于Internet上的控制文件的双向传输。FTP提供交互式的访问,允许客户指明文件类型与格式,并允许文件具有存取权限。FTP屏蔽了各计算机系统的细节,因而适合于在异构网络中计算机之间传送文件。

二、FTP服务特点

1、文件传送协议FTP只提供文件传送的一些基本的服务,它使用TCP可靠的运输方式。

2、FTP的主要功能是减少或消除在不同操作系统下处理文件的不兼容性。

3、FTP使用客户服务器方式。一个FTP服务器进程可同时为多个客户进程提供服务,FTP的服务器进程由二大部分组成:一个是主进程,负责接受新的请求;另外有诺干个从属进程,负责处理单个请求

三、实验环境搭建

为了更透彻的理解和掌握FTP,在叙述FTP协议内容的同时,以“实战 ” 的方式抓取FTP客户端FTP服务端之间交互的网络包,以此和FTP协议相互印证,加深理解。本节主要介绍抓取FTP网络包的环境搭建。实验环境将以linux系统虚拟机的一个编译界面作为FTP客户端,以linux系统虚拟机的另一个编译界面作为FTP服务器。

四、常用FTP命令行

  • ftp 服务器域名(ip地址),如:ftp ftp.gnu.org,进行FTP服务器登录;
  • ftp>? 或 ftp>help,显示"ftp"命令行说明;
  • ftp>dir,显示FTP服务端目录文件和子目录列表;
  • ftp>cd,切换FTP服务端上的工作目录;
  • ftp>ls,显示FTP服务端上目录文件和子目录的缩写列表;
  • ftp>pwd,显示FTP服务端上的当前目录;
  • ftp>lcd,切换FTP客户端上的工作目录;
  • ftp>lls,显示FTP客户端上目录文件和子目录的缩写列表;
  • ftp>lpwd,显示FTP客户端上的当前目录;
  • ftp>ldir,显示FTP客户端目录文件和子目录列表;

五、项目实现思路

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

六、相关函数

1、socket():创建一个网络通信端点

函数原型

int socket(int domain,int type, int protocol);

参数解读

  • domain:指明所使用的协议族/域。

常用的domain类型有:

  • AF_INET IPv4——因特网域
  • AF_INET6 IPv6——因特网域
  • AF UNIX Unix——域
  • AF ROUTE——路由套接字
  • AFKEYE——钥套接字
  • AF UNSPEC——未拖定
  • type:指定socket类型。

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

  • protocol:通常赋值 0

0表示选择type类型对应得默认协议。

  • IPPROTO_TCP——TCP传输协议
  • IPPTOTO_UDP——UDP传输协议
  • IPPROTO_SCTP——STCP传输协议
  • IPPROTO_TIPC——TIPC传输协议

返回值

成功时返回新的套接字描述符,失败返回 -1。

2、atoi():将字符串转变成整型数据

函数原型

int atoi(const char *nptr);

参数解读

const char *nptr:需要进行转换的字符串

返回值

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

3、htons():将16位无符号数从主机字节序转换成网络字节序

函数原型

uint16_t htons(uint16_t hostshort);

参数解读

uint16_t hostshort:16位无符号整数。

返回值

转换之后的TCP/IP网络字节序。

4、inet_aton():将IP地址从字符串类型转换成网络字节序

函数原型

int inet_aton(const char *cp, struct in_addr *inp);

参数解读

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

返回值

调用成功返回非0,调用失败返回0。

5、inet_ntoa():将IP地址从网络字节序转换成字符串类型

函数原型

char *inet_ntoa(struct in_addr in);

参数解读

struct in_addr insockaddr_in类型结构体里的in_addr类型结构体

返回值

指向字符串类型IP地址的字符串指针

6、bind():为套接字添加信息(协议族、IP地址、端口号)

函数原型

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

参数解读

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

返回值

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

7、listen():监听客户端的连接

函数原型

int listen(int sockfd, int backlog);

参数解读

  • int sockfd:套接字描述符
  • int backlog:指定在请求队列中允许的最大连接数

返回值

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

8、accept():等待客户端的连接,当没有客户端连接时,accept()会阻塞等待

函数原型

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数解读

  • int sockfd:套接字描述符
  • const struct sockaddr *addr:sockaddr类型结构体地址
  • socklen_t *addrlen:参数二内存空间大小的值的地址

返回值

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

9、connect():客户端连接服务器

函数原型

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

参数解读

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

返回值

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

10、fork():创建一个子进程

函数原型

pid_t fork(void);

fork函数调用成功,返回两次PID

(1)返回值为0,代表当前进程是子进程

(2)返回值为非负数,代表当前进程是父进程

(3)调用失败,则返回-1

11、open():打开一个文件

函数原型

int open(const char *pathname, int flags, mode_t mode);

参数解读

  • const char *pathname:文件名(相对路径)
  • int flags:打开文件的方式及附带操作
  • mode_t mode:(可选参数)文件访问的权限

返回值

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

12、write():向某个文件写入数据

函数原型

int write(int fd, const void *buf, size_t count);

参数解读

  • fd:文件描述符
  • void *buf:写入文件的数据
  • size_t count:写入文件的字节数

 返回值

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

13、lseek():移动文件的光标,通常用lseek(fd,0,SEEK_END)获取文件长度

函数原型

int lseek(int fd, off_t offset, int whence);

参数解读

  • fd:文件描述符
  • off_t offset:偏移字节,0为不偏移,-a为往前偏移a个字节,b为往前偏移b个字节
  • int whence:光标位置

返回值

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

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

参数解读

fd:文件描述符

返回值

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

15、strtok():字符串分割函数

函数原型

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

参数解读

  • char *str:字符串
  • const char *delim:分隔符

返回值

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

16、strcmp():字符串比较函数

函数原型

int strcmp(const char *s1, const char *s2);

参数解读

  • const char *s1:字符串1
  • const char *s2:字符串2

返回值

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

17、strstr():字符串包含函数

函数原型

char *strstr(const char *s1, const char *s2);

参数解读

  • const char *s1:字符串1
  • const char *s2:字符串2

返回值

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

 18、strcat():字符串拼接函数

函数原型

char *strcat(char *str1, const char *str2);

参数解读

  • const char *s1:字符串1
  • const char *s2:字符串2

返回值

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

 
19、strcpy():字符串复制函数

函数原型

char *strcpy(char *str1, const char *str2);

参数解读

  • const char *s1:字符串1
  • const char *s2:字符串2

返回值

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

 20、memset():将一块内存设定成指定的值

函数原型

void *memset(void *s, int c, size_t n);

参数解读

  • void *s:内存块
  • int c:指定值(一般设置0)
  • size_t n:要被设置该值的字符数(字符数大小sizeof)

返回值

返回一个指向内存s的指针。

 21、system():执行某个命令,命令执行后继续从调用点执行程序

函数原型

int system(const char *command);

参数解读

const char *command:命令

返回值

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

22、popen():执行某个命令,并将执行命令后得到的数据存放到一个文件流中

函数原型

FILE *popen(const char *command, const char *type);

参数:

  • const char *command:命令
  • const char *type:返回的文件流权限,w:文件流可写,r: 文件流可读(与system等价)

返回值

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

 23、fread():从某个文件流中读取数据

函数原型

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

参数解读

  • const void *ptr:读取数据存放位置
  • size_t size:每次读的字节数
  • size_t nmemb:读的次数
  • FILE *stream:文件流

返回值

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

 24、fflush():刷新缓冲区,将某个流未写的数据传送至内核

函数原型

int fflush(FILE *stream);

参数解读

FILE *stream:文件流

返回值

调用成功返回0,调用失败返回EOF。

25、fflush(stdin):刷新标准输入缓冲区,把输入缓冲区里的东西丢弃
26、fflush(stdout):刷新标准输出缓冲区,把输出缓冲区里的东西强制打印到标准输出设备上
27、chdir():修改当前的工作目录

函数原型

int chdir(const char *path);

参数解读

const char *path:新的当前工作目录,绝对路径或者相对路径

返回值

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

 28、access():查看文件是否具有某个权限

函数原型

int access(const char * pathname,int mode);

参数解读

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

返回值

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

七、代码示例

服务端
#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 <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 15struct 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.socketint 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.bindint 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.listenint 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.acceptc_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 15int 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.cmdstrcat(file_path,str_decompose(msg.cmd)); // ./1.c->file_pathmemset(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.socketint 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.connectif(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.mzph.cn/news/580427.shtml

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

相关文章

File Inclusion(Pikachu)

File Inclusion(local) 这里随便点击一个提交 观察url&#xff0c;显示是一个文件file1.php 可以直接通过url修改这个文件 找到自己的文件&#xff08;本地文件&#xff09;shell.php的路径写上去 就可以看到 File Inclusion&#xff08;remote&#xff09; 提交的是一个目标…

大带宽服务器怎么选

大带宽服务器怎么选 在选择时&#xff0c;需要考虑的因素包括&#xff1a;   - 业务需求&#xff1a;不同的业务类型对服务器的性能要求不同。例如&#xff0c;文件和数据库服务器、邮件服务器、web服务器、多媒体服务器、终端服务器的需求就各不相同。   - 成本&#xff1…

C#教程(四):多态

1、介绍 1.1 什么是多态 在C#中&#xff0c;多态性&#xff08;Polymorphism&#xff09;是面向对象编程中的一个重要概念&#xff0c;它允许不同类的对象对同一消息做出响应&#xff0c;即同一个方法可以在不同的对象上产生不同的行为。C#中的多态性可以通过以下几种方式实现…

JVM基础篇---02

为什么需要用户自定义类加载器&#xff1a; 扩展类加载器的功能&#xff1a; Java的默认类加载器主要有三个&#xff0c;分别是引导类加载器、扩展类加载器和应用程序类加载器。其中&#xff0c;引导类加载器和扩展类加载器是由JVM实现的&#xff0c;用户无法修改其行为。而应用…

促进家校沟通的方法有哪些

“家校沟通是教育中的重要一环&#xff0c;它可以帮助教师和家长更好地了解和关心孩子&#xff0c;共同促进孩子的健康成长。但是&#xff0c;在实际操作中&#xff0c;如何才能有效地促进家校沟通呢&#xff1f; 定期家长会&#xff1a;每个学期开始和结束时&#xff0c;以及期…

【Unity6.0+AI】Sentis加载模型识别手写数字案例实现

按照国际惯例,看效果: 素材准备: 自己在PS中绘制黑底白字手写字体,导出jpg,尺寸28*28! 素材设置 基本步骤 准备工作:从 ONNX Model Zoo 下载手写识别 ONNX 模型文件 【下载模型】MNIST 手写数字识别模型 mnist-12.onnx,并将其拖入项目窗口的 Assets 文件夹。 【下载模…

vue根据身份证获取年龄/生日/性别,根据年龄获取生日,根据生日获取年龄

首先根据身份证获取年龄/生日/性别 handleBlur(data) {let idCard data.target.value;let sex null;let birth null;let myDate new Date();let month myDate.getMonth() 1;let day myDate.getDate();let age 0;if (idCard.length 18) {age myDate.getFullYear() - i…

每日一题-----逆序字符串

大家好我是Beilef&#xff0c;在一个美好的下午我意外接触到编程并且产生了兴趣&#xff0c;哈哈我要努力成为一个跨界者&#xff0c;让我们一起加油吧O(∩_∩)O 文章目录 目录 文章目录 前言 大家好请上车 一、逆序字符串 题⽬描述&#xff1a; 输⼊⼀个字符串&#xff0c;写…

7.7、kali linux环境下搭建DVWA

目录 一、资料下载准备工作 1.1、DVWA源代码下载 二、开启Apache、mysql服务 2.1、下载Apache2文件 2.2、开启Apache2服务 方法一&#xff1a;开启Apache2服务&#xff08;手动&#xff09; 方法二&#xff1a;开启Apache2服务&#xff08;系统自启动&#xff09; 2.3、…

量子密码学简介

量子密码学&#xff08;英语&#xff1a;Quantum cryptography&#xff09;泛指利用量子力学的特性来加密的科学。量子密码学最著名的例子是量子密钥分发&#xff0c;而量子密钥分发提供了通信两方安全传递密钥的方法&#xff0c;且该方法的安全性可被信息论所证明。目前所使用…

blackbox黑盒监控部署(k8s内)tensuns专用

一、前言 部署在k8s中需要用到deployment、configmap、service服务 二、部署 创建存放yaml的目录 mkdir /opt/blackbox-exporter && cd /opt/blackbox-exporter 编辑blackbox配置文件&#xff0c;使用configmap挂在这 vi configmap.yaml apiVersion: v1 kind: Confi…

连续时间LQR和离散时间LQR笔记

文章目录 连续时间LQR理解离散时间LQR理解参考资料 本文是根据下面参考资料里的1和2对应的讲座内容所做的笔记 连续时间LQR理解 假设一个系统可以被表示为如下形式的状态方程&#xff1a; x ˙ A x B u ( 1.1 ) \dot{x} Ax Bu \qquad \qquad (1.1) x˙AxBu(1.1) 式中的 x…

C#与VisionPro联合编程

C#与VisionPro联合 1. 参照康耐视提供的样例2. 参照样例写一个1. 创建工程2. 添加引用3. 声明变量4. 初始化5. 刷新队列6. 用户数据获取7. 跨线程访问Windows控件--委托8. 显示图像9. 释放资源 3. 代码4. 资源下载 1. 参照康耐视提供的样例 C:\Program Files\Cognex\VisionPro…

详解Java多线程、线程池及线程同步(synchronized关键字、悲观锁、乐观锁)——通俗易懂版!!!

1.进程与线程定义 进程包含线程&#xff0c;如一个百度网盘进程&#xff0c;该进程的线程可以有上传&#xff0c;下载。 2.创建线程的三种方式 方式1-继承Thread类 方式2-实现Runnabled接口 1.常规写法 2.匿名内部类写法 方式3-实现Callable接口 示例代码&#xff1a; f1.get…

CAD objectArx 在操作mfc时出现“不支持尝试执行的操作“

问题原因&#xff1a; ARX中对话框通常继承自CAcUiDialog&#xff0c;CAcUiDialog 构造函数有个参数 HINSTANCE hInstance&#xff0c;默认为 NULL&#xff0c;指定了对话框资源所在DLL进程。如果没有指定该参数&#xff0c;在创建对话框&#xff08;DoModal或Create&#xff…

湘潭大学-软件工程-大题浅析

前言 因为打印的资料只有少数几份有答案&#xff0c;所以这个部分比较简短 大题包括分析&#xff0c;设计&#xff0c; UML图&#xff0c;四个大题&#xff0c;占40分 应用设计题 1.建立软件公司的对象模型 矩形方框表示对象&#xff0c;只需要把题干所有信息用图表示出来即…

记一次应急响应练习(windows)

记一次应急响应练习&#xff08;windows&#xff09; windows&#xff1a; 1.请提交攻击者攻击成功的第一时间&#xff0c;格式&#xff1a;YY:MM:DD hh:mm:ss 答&#xff1a;2023/04/29:22:44:32 思路&#xff1a; 看见桌面的小皮面板&#xff0c;进入小皮的安装目录。发现…

IDEA相关操作

目录 连接MySQL IDEA配置Maven 配置全局Maven 导入Maven项目 方法一 方法二 安装Mybatisx插件 连接MySQL 填写user和Password之后测试连接 如果是第一次连接需要联网下载数据库连接驱动&#xff0c;安装提示下载即可 如果显示如下错误需要更改时区 Server returns …

2024 年 11 款最佳 Android 数据恢复软件应用

Android 设备上的数据丢失可能是一种令人痛苦的经历&#xff0c;通常会导致不可替代的信息瞬间消失。 意外删除、系统崩溃或格式错误都可能发生&#xff0c;重要数据的丢失可能会扰乱日常工作并影响您的工作效率。 幸运的是&#xff0c;技术进步带来了多种恢复解决方案&…

搭建谷歌 Gemini,体验谷歌版GPT4

12.06 日谷歌 DeepMind CEO 和联合创始人 Demis Hassabis 正式推出了大模型Gemini 目前&#xff0c;Gemini 1.0 提供了三个不同的尺寸版本&#xff0c;分别如下&#xff1a; Gemini Ultra&#xff1a;规模最大、能力最强&#xff0c;用于处理高度复杂的任务&#xff1b;Gemin…