首先我们得知道什么是FTP服务器,它是干什么的。FTP服务器,是在互联网上提供存储空间的计算机,它们依照FTP协议提供服务。 FTP的全称是File Transfer Protocol(文件传输协议)。顾名思义,就是专门用来传输文件的协议。大家如果想详细了解可以自行百度。
接下来呢我们就通过socket套接字网络编程来模拟实现一下FTP服务器的简单功能:
ftp_server.c:
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "Config.h"
//int Flag = 0;
char* GetDir(char *cmd)
{
char *file;
file = strtok(cmd," ");
file = strtok(NULL," ");
return file;
}
int GetcmdType(char *cmd)
{
if(strstr(cmd,"lcd")) return LCD;
if(!strcmp("ls",cmd)) return LS;
if(!strcmp("pwd",cmd)) return PWD;
if(strstr(cmd,"cd")) return CD;
if(!strcmp("lls",cmd)) return LLS;
if(!strcmp("lpwd",cmd)) return LPWD;
//if(strstr(cmd,"lcd")) return LCD;
if(strstr(cmd,"get")) return GET;
if(strstr(cmd,"put")) return PUT;
if(!strcmp("quit",cmd)) return QUIT;
}
void Do_Cmd(int fd,char *cmd)
{
int type;
int filefd;
int newfilefd;
FILE *stream;
char *file;
type = GetcmdType(cmd);
printf("cmd : %s\n",cmd);
switch(type)
{
case LS:
case PWD:
stream = popen(cmd,"r");
fread(DATA,sizeof(DATA),1,stream);
write(fd,DATA,sizeof(DATA));
memset(DATA,0,sizeof(DATA));
break;
case CD:
file = GetDir(cmd);
strcpy(DATA,file);
write(fd,DATA,sizeof(DATA));
memset(DATA,0,sizeof(DATA));
chdir(file);
break;
case LLS:
case LPWD:
case LCD:
break;
case GET:
file = GetDir(cmd);
if(access(file,F_OK) == -1)
{
strcpy(DATA,"This file does not exist\n");
write(fd,DATA,sizeof(DATA));
}
else
{
filefd = open(file,O_RDWR);
lseek(filefd,0,SEEK_SET);
read(filefd,DATA,sizeof(DATA));
write(fd,DATA,sizeof(DATA));
close(filefd);
}
memset(DATA,0,sizeof(DATA));
break;
case PUT:
file = GetDir(CMD);
newfilefd = open(file,O_RDWR|O_CREAT,0666);
read(fd,DATA,sizeof(DATA));
write(newfilefd,DATA,sizeof(DATA));
close(newfilefd);
memset(DATA,0,sizeof(DATA));
break;
case QUIT:
printf("client exits\n");
exit(-1);
}
}
int main(int argc,char **argv)
{
int s_fd;
int c_fd;
int n_read;
int length;
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
if (argc != 3)
{
printf("params is error\n");
exit(-1);
}
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
s_fd = socket(AF_INET, SOCK_STREAM, 0);
if (s_fd == -1)
{
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&s_addr.sin_addr);
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
listen(s_fd,10);
length = sizeof(struct sockaddr_in);
while(1)
{
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&length);
if (c_fd == -1)
{
perror("accept");
exit(-1);
}
printf("get connect: %s\n",inet_ntoa(c_addr.sin_addr));
if (fork() == 0)
{
while(1)
{
memset(CMD,0,sizeof(CMD));
n_read = read(c_fd,&CMD,sizeof(CMD));
if (n_read == 0)
{
printf("client quit\n");
break;
}
else if (n_read > 0)
{
Do_Cmd(c_fd,CMD);
}
}
}
}
close(s_fd);
close(c_fd);
return 0;
}
ftp_client.c:
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "Config.h"
char* GetDir(char *cmd)
{
char *file;
file = strtok(cmd," ");
file = strtok(NULL," ");
return file;
}
int GetcmdType(char *cmd)
{
if(strstr(cmd,"lcd")) return LCD;
if(!strcmp("ls",cmd)) return LS;
if(!strcmp("pwd",cmd)) return PWD;
if(strstr(cmd,"cd")) return CD;
if(!strcmp("lls",cmd)) return LLS;
if(!strcmp("lpwd",cmd)) return LPWD;
//if(strstr(cmd,"lcd")) return LCD;
if(strstr(cmd,"get")) return GET;
if(strstr(cmd,"put")) return PUT;
if(!strcmp("quit",cmd)) return QUIT;
}
void Do_Cmd(int fd,char *cmd)
{
int type;
char *file;
int filefd;
int newfilefd;
type = GetcmdType(cmd);
switch(type)
{
case LS:
case PWD:
case CD:
write(fd,CMD,sizeof(CMD));
read(fd,DATA,sizeof(DATA));
printf("cmd result:\n");
printf("%s\n",DATA);
//fflush(stdout);
memset(DATA,0,sizeof(DATA));
break;
case LLS:
write(fd,CMD,sizeof(CMD));
system("ls");
break;
case LPWD:
write(fd,CMD,sizeof(CMD));
system("pwd");
break;
case LCD:
write(fd,CMD,sizeof(CMD));
file = GetDir(cmd);
chdir(file);
break;
case GET:
write(fd,CMD,sizeof(CMD));
read(fd,DATA,sizeof(DATA));
if(strstr(DATA,"This file does not exist"))
{
printf("%s\n",DATA);
}
else
{
file = GetDir(cmd);
newfilefd = open(file,O_RDWR|O_CREAT,0600);
write(newfilefd,DATA,sizeof(DATA));
close(newfilefd);
Flag = 0;
}
memset(DATA,0,sizeof(DATA));
break;
case PUT:
write(fd,CMD,sizeof(CMD));
file = GetDir(CMD);
if(access(file,F_OK) == -1)
{
printf("This file does not exist\n");
}
else
{
filefd = open(file,O_RDWR);
read(filefd,DATA,sizeof(DATA));
write(fd,DATA,sizeof(DATA));
close(filefd);
}
memset(DATA,0,sizeof(DATA));
break;
case QUIT:
write(fd,CMD,sizeof(CMD));
close(fd);
exit(-1);
}
}
int main(int argc,char **argv)
{
int c_fd;
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
if(argc != 3)
{
printf("param is not good\n");
exit(-1);
}
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);
//2.connect
if(connect(c_fd, (struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1)
{
perror("connect");
exit(-1);
}
printf("Connecting ......\n");
while(1)
{
memset(CMD,0,sizeof(CMD));
printf("Input cmd:");
gets(CMD);
Do_Cmd(c_fd,CMD);
}
return 0;
}
ftp_client.c运行结果:
ftp_server.c运行结果:
该项目主要运用到了linux文件编程、linux进程间通信和linux网络编程的相关知识点,大家有兴趣的可以看看我之前的文章,在此就不过多赘述了。这里新用到的函数有:strtok函数和chdir函数,前者可以做到分割字符串从而获得文件名,后者可以进入到目标文件夹目录下,用到一次就积累一次吧。
以上就是这个项目的完整内容,希望对大家有所帮助。