基于socket的ftp实现(一)
服务器端的实现:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>//sockaddr_in等结构的定义
#include <netdb.h>//addrinfo等结构的定义
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#define TRUE 1
#define LISTEN_PORT 3499
#define dataLen 1024
char currentDirPath[200];
char currentDirName[30];
char help[]="get get a file from server\n\
put upload a file to server\n\
pwd display the current directory of server\n\
dir display the files in the current directory of server\n\
cd change the directory of server\n\
? display the whole command which equals 'help'\n\
quit return\n";
char *getDirName(char *dirPathName);
void cmd_pwd(int sock);
void cmd_dir(int sock);
void cmd_cd(int sock,char *dirName);
void cmd_cdback(int sock);
void cmd_help(int sock);
void cmd_get(int sock,char*fileName);
void cmd_put(int sock,char *fileName);
int main(int argc,char *argv[])
{
int sock,sockmsg, length, lengthmsg;
char client_cmd[10] , cmd_arg[20];
struct sockaddr_in server;
struct sockaddr_in servermsg;
int datasock, msgsock;
pid_t child;
// int datasock; //data socket
int rval;
sock=socket(AF_INET,SOCK_STREAM,0);//创建流式套接字
sockmsg=socket(AF_INET,SOCK_STREAM,0);
if (sock<0||sockmsg<0)
{
perror("opening stream socket");
exit(1);
}
server.sin_family=AF_INET;//AF_INET针对internet,另一种形式AF_UNIX只能够用于单一的Unix系统进程通信(主机通信协议)
server.sin_addr.s_addr=INADDR_ANY;//表示可以和任何主机通信
server.sin_port=htons(LISTEN_PORT);//htons将短整形数据转换位网络字节顺序
servermsg.sin_family=AF_INET;
servermsg.sin_addr.s_addr=INADDR_ANY;
servermsg.sin_port=htons(LISTEN_PORT+1);
if (bind(sock,(struct sockaddr *)&server,sizeof server)<0||bind(sockmsg,(struct sockaddr *)&servermsg,sizeof servermsg)<0)//将本地端口与socket返回的文件描述符绑定在一起
{
perror("binding stream socket");
exit(1);
}
length=sizeof server;
lengthmsg=sizeof servermsg;
if (getsockname(sock,(struct sockaddr *)&server,&length)<0||getsockname(sockmsg,(struct sockaddr *)&servermsg,&lengthmsg)<0)//用于得套接口的名字
{
perror("getting socket name");
exit(1);
}
printf("Socket port # %d %d\n",ntohs(server.sin_port),ntohs(servermsg.sin_port));
memset(currentDirPath,0,sizeof(currentDirPath));//将currentDirpath置零
getcwd(currentDirPath,sizeof(currentDirPath));//得到当前路径,保存在currentDirPath中
listen(sock,2); //监听,允许最大监听数位2,将绑定的套接字变成监听套接字
listen(sockmsg,2);
do
{
datasock = accept(sock,(struct sockaddr*)0,(int*)0);//接受请求
msgsock = accept(sockmsg,(struct sockaddr*)0,(int*)0);
if (datasock == -1||msgsock==-1)
perror("accept");
else
{
if((child=fork())==-1)//创建子进程
{
printf("Fork Error!\n");
}
//The child process
if(child==0)
{
printf("connection accepted! new client comming\n");
loop:
memset(client_cmd,0,sizeof(client_cmd));
rval=0;
rval=read(msgsock,client_cmd,sizeof(client_cmd));//从msgsock中读取数据到client_cmd
if(rval<0)
{
perror("reading command failed\n");
}
else if(rval==0)
{
printf("connection closed.\n");
close(datasock);//关闭套接字
close(msgsock);
}
else
{
if(strcmp(client_cmd,"pwd")==0)
{
printf("cmmand pwd\n");
cmd_pwd(datasock);
printf("done\n\n");
goto loop;
}
else if(strcmp(client_cmd,"dir")==0)
{
printf("command dir\n");
cmd_dir(datasock);
printf("done\n\n");
goto loop;
}
else if(strcmp(client_cmd,"cd")==0)
{
printf("command cd\n");
//read the argument
memset(cmd_arg,0,sizeof(cmd_arg));
read(msgsock,cmd_arg,sizeof(cmd_arg));
cmd_cd(datasock,cmd_arg);
printf("done\n\n");
goto loop;
}
else if(strcmp(client_cmd,"cd..")==0)
{
printf("command cd..\n");
cmd_cdback(datasock);
printf("done\n\n");
goto loop;
}
else if(strcmp(client_cmd,"get")==0)
{
printf("command get\n");
memset(cmd_arg,0,sizeof(cmd_arg));
read(msgsock,cmd_arg,sizeof(cmd_arg));
cmd_get(datasock,cmd_arg);
printf("done\n\n");
goto loop;
}
else if(strcmp(client_cmd,"put")==0)
{
printf("command put\n");
memset(cmd_arg,0,sizeof(cmd_arg));
read(msgsock,cmd_arg,sizeof(cmd_arg));
cmd_put(datasock,cmd_arg);
printf("done\n\n");
goto loop;
}
else if(strcmp(client_cmd,"?")==0)
{
printf("command ?\n");
cmd_help(datasock);
printf("done\n\n");
goto loop;
}
else if(strcmp(client_cmd,"quit")==0)
{
printf("quit\n");
goto endchild;
}
else
{
printf("bad request!\n");
goto loop;
}
}
endchild:
printf("connection closed.\n");
close(datasock);
close(msgsock);
exit(0);
}
}
}while(TRUE);
exit(0);
}
//pwd command
void cmd_pwd(int sock)
{
int len;
memset(currentDirPath,0,sizeof(currentDirPath));
getcwd(currentDirPath,sizeof(currentDirPath));
char *savePointer=getDirName(currentDirPath);
strcpy(currentDirName,savePointer);
len=strlen(currentDirName)+1;
write(sock,currentDirName,len);
}
//dir command
void cmd_dir(int sock)
{
DIR *pdir; //目录结构
char fileName[30];
char fileInfo[50];
int i, fcounts=0, len;
struct dirent *pent;//目录的结构体属性
int fd;
struct stat fileSta;//文件属性
char filePath[200];
pdir=opendir(currentDirPath);//打开目录
pent=readdir(pdir);//读取目录
while(pent!=NULL)
{
fcounts++;//计算文件个数
pent=readdir(pdir);
}
write(sock,&fcounts,sizeof(int));//将文件个数写入sock
closedir(pdir);//关闭目录
if(fcounts<=0)
{
return;
}
else
{
pdir=opendir(currentDirPath);
for(i=0;i<fcounts;i++)
{
pent=readdir(pdir);
memset(fileName,0,30);
memset(fileInfo,0,sizeof(fileInfo));
strcpy(fileName,pent->d_name);
//check the file is a directory or a file
memset(filePath,0,sizeof(filePath));
strcpy(filePath,currentDirPath);
strcat(filePath,"/");//链接两个字符串
strcat(filePath,fileName);
fd=open(filePath,O_RDONLY, S_IREAD);
fstat(fd,&fileSta);//用来读取打开的文件的属性,stat用来读取没有打开的文件的属性
if(S_ISDIR(fileSta.st_mode))//判断文件是否为目录
{
strcat(fileInfo,"dir\t");
strcat(fileInfo,fileName);
}
else
{
strcat(fileInfo,"file\t");
strcat(fileInfo,fileName);
}
write(sock,fileInfo,sizeof(fileInfo));
}
closedir(pdir);
}
}
//command cd
void cmd_cd(int sock,char *dirName)
{
DIR *pdir;
struct dirent *pent;
char filename[30];
int i,fcounts=0;
int flag=0;
pdir=opendir(currentDirPath);
pent=readdir(pdir);
while(pent!=NULL)
{
fcounts++;
pent=readdir(pdir);
}
closedir(pdir);
if(fcounts<=0)
{
return;
}
else
{
pdir=opendir(currentDirPath);
for(i=0;i<fcounts;i++)
{
pent=readdir(pdir);
if(strcmp(pent->d_name,dirName)==0)
{
strcat(currentDirPath,"/");
strcat(currentDirPath,dirName);
flag=1;
break;
}
}
if(flag==1)
{
write(sock,currentDirPath,sizeof(currentDirPath));
}
closedir(pdir);
}
}
//command cd..
void cmd_cdback(int sock)
{
int len;
int i, record;
len=strlen(currentDirPath);
for(i=len-1;i>=0;i--)
{
if(currentDirPath[i]=='/')
{
currentDirPath[i]='\0';
break;
}
currentDirPath[i]='\0';
}
}
//command ?
void cmd_help(int sock)
{
int len=strlen(help)+1;
write(sock,help,len);
}
//command get
void cmd_get(int sock,char*fileName)
{
int fd;
struct stat fileSta;
long fileSize;
char filePath[200], buf[dataLen];
memset(filePath,0,sizeof(filePath));
strcpy(filePath,currentDirPath);
strcat(filePath,"/");
strcat(filePath,fileName);
fd=open(filePath,O_RDONLY, S_IREAD);
if(fd!=-1)
{
fstat(fd,&fileSta);
fileSize=(long) fileSta.st_size;//?
write(sock,&fileSize,sizeof(long));
memset(buf,0,dataLen);
while(fileSize>dataLen)
{
read(fd,buf,dataLen);
write(sock,buf,dataLen);
fileSize=fileSize-dataLen;
}
read(fd,buf,fileSize);
write(sock,buf,fileSize);
close(fd);
printf("transfer completed\n");
}
else
{
printf("open file %s failed\n",filePath);
}
}
//command put
void cmd_put(int sock,char *fileName)
{
int fd;
long fileSize;
char filePath[200], buf[dataLen];
strcpy(filePath,currentDirPath);
strcat(filePath,"/");
strcat(filePath,fileName);
fd=open(filePath,O_RDWR|O_CREAT, S_IREAD|S_IWRITE);
if(fd!=-1)
{
memset(buf,0,dataLen);
read(sock,&fileSize,sizeof(long));
while(fileSize>dataLen)
{
read(sock,buf,dataLen);
write(fd,buf,dataLen);
fileSize=fileSize-dataLen;
}
read(sock,buf,fileSize);
write(fd,buf,fileSize);
close(fd);
printf("transfer completed\n");
}
else
{
printf("open file %s failed\n",filePath);
}
}
//get the last string after the last char '/'
char *getDirName(char *dirPathName)
{
int i, pos, len;
char *dirName;
if(dirPathName==NULL)
{
printf("directory absoultly path is null!\n");
return NULL;
}
len=strlen(dirPathName);
for(i=len-1;i>=0;i--)
{
if(dirPathName[i]=='/')
{
pos=i;
break;
}
}
dirName=(char *)malloc(len-pos+1);
for(i=pos+1;i<len;i++)
{
dirName[i-pos-1]=dirPathName[i];
}
return dirName;
}
客户端实现:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#define TRUE 1
#define dataLen 1024
char user_cmd[10],cmd_arg[20];
char buf[dataLen];
void cmd_pwd(int sock,int sockmsg);
void cmd_dir(int sock,int sockmsg);
void cmd_cd(int sock,int sockmsg,char *dirName);
void cmd_cdback(int sock,int sockmsg);
void cmd_help(int sock,int sockmsg);
void cmd_get(int sock,int sockmsg,char *fileName);
void cmd_put(int sock,int sockmsg,char *fileName);
void cmd_quit(int sock,int sockmsg);
int main(int argc,char *argv[])
{
int cmd_len,arg_len;
int sock, sockmsg;
struct sockaddr_in server, servermsg;
struct hostent *hp;
sock=socket(AF_INET,SOCK_STREAM,0);
sockmsg=socket(AF_INET,SOCK_STREAM,0);
if (sock<0||sockmsg<0)
{
perror("opening stream socket");
exit(1);
}
hp = gethostbyname(argv[1]);
if (hp==0)
{
fprintf(stderr,"%s:unknown host\n",argv[1]);
exit(2);
}
server.sin_family=AF_INET;
server.sin_port=htons(atoi(argv[2]));
memcpy((char*)&server.sin_addr, (char*)hp->h_addr, hp->h_length);
servermsg.sin_family=AF_INET;
servermsg.sin_port=htons(atoi(argv[2])+1);
memcpy((char*)&servermsg.sin_addr, (char*)hp->h_addr, hp->h_length);
if (connect(sock,(struct sockaddr *)&server,sizeof server)<0||connect(sockmsg,(struct sockaddr *)&servermsg,sizeof servermsg)<0)
{
perror("connecting stream socket");
exit(1);
}
//Get command from command line and do just the action
while(TRUE)
{
memset(user_cmd,0,10);
memset(cmd_arg,0,20);
//First get the input character by user
printf("command: ");
scanf("%s",user_cmd);
cmd_len=strlen(user_cmd);
//Then get the command character and the argument
if(strcmp(user_cmd,"quit")==0) //command "quit"
{
cmd_quit(sock,sockmsg);
close(sockmsg);
close(sock);
printf("connection closed\n\n");
exit(0);
}
else if(strcmp(user_cmd,"?")==0) //command "?"
{
cmd_help(sock,sockmsg);
}
else if(strcmp(user_cmd,"pwd")==0) //command "pwd"
{
cmd_pwd(sock,sockmsg);
}
else if(strcmp(user_cmd,"dir")==0) //command "dir"
{
cmd_dir(sock,sockmsg);
}
else if(strcmp(user_cmd,"cd")==0) //commad "cd"
{
//input command argument
scanf("%s",cmd_arg);
cmd_cd(sock,sockmsg,cmd_arg);
}
else if(strcmp(user_cmd,"cd..")==0)
{
cmd_cdback(sock,sockmsg);
}
else if(strcmp(user_cmd,"get")==0) //command "get"
{
//input command argument
scanf("%s",cmd_arg);
cmd_get(sock,sockmsg,cmd_arg);
}
else if(strcmp(user_cmd,"put")==0) //command "put"
{
//input command argument
scanf("%s",cmd_arg);
cmd_put(sock,sockmsg,cmd_arg);
}
else
{
printf("bad command!\n");
}
}
}
//command pwd
void cmd_pwd(int sock,int sockmsg)
{
//int numRead;
char dirName[30];
write(sockmsg,user_cmd,sizeof(user_cmd));
read(sock,dirName,30);
printf("%s\n",dirName);
}
//command dir
void cmd_dir(int sock, int sockmsg)
{
int i, fileNum=0;
char fileInfo[50];
write(sockmsg,user_cmd,sizeof(user_cmd));
read(sock,&fileNum,sizeof(int));
printf("--------------------------------------------------------\n");
printf("file number : %d\n",fileNum);
if(fileNum>0)
{
for(i=0;i<fileNum;i++)
{
memset(fileInfo,0,sizeof(fileInfo));
read(sock,fileInfo,sizeof(fileInfo));
printf("%s\n",fileInfo);
}
printf("--------------------------------------------------------\n");
}
else if(fileNum==0)
{
printf("directory of server point is empty.\n");
return;
}
else
{
printf("error in command 'dir'\n");
return;
}
}
//command cd
void cmd_cd(int sock,int sockmsg,char *dirName)
{
char currentDirPath[200];
write(sockmsg,user_cmd,sizeof(user_cmd));
write(sockmsg,cmd_arg,sizeof(cmd_arg));
read(sock,currentDirPath,sizeof(currentDirPath));
printf("now in directory : %s\n",currentDirPath);
}
//command cd..
void cmd_cdback(int sock,int sockmsg)
{
write(sockmsg,user_cmd,sizeof(user_cmd));
}
//command quit
void cmd_quit(int sock,int sockmsg)
{
write(sockmsg,user_cmd,sizeof(user_cmd));
}
//command help
void cmd_help(int sock, int sockmsg)
{
char help[300];
write(sockmsg,user_cmd,sizeof(user_cmd));
read(sock,help,300);
printf("%s\n",help);
}
//command get
void cmd_get(int sock,int sockmsg,char *fileName)
{
int fd;
long fileSize;
char localFilePath[200];
write(sockmsg,user_cmd,sizeof(user_cmd));
write(sockmsg,cmd_arg,sizeof(cmd_arg));
printf("%s\n%s\n",user_cmd,cmd_arg);
memset(localFilePath,0,sizeof(localFilePath));
getcwd(localFilePath,sizeof(localFilePath));
strcat(localFilePath,"/");
strcat(localFilePath,fileName);
fd=open(localFilePath,O_RDWR|O_CREAT, S_IREAD|S_IWRITE);
if(fd!=-1)
{
memset(buf,0,dataLen);
read(sock,&fileSize,sizeof(long));
while(fileSize>dataLen)
{
read(sock,buf,dataLen);
write(fd,buf,dataLen);
fileSize=fileSize-dataLen;
}
read(sock,buf,fileSize);
write(fd,buf,fileSize);
close(fd);
printf("download completed\n");
}
else
{
printf("open file %s failed\n",localFilePath);
}
}
//command put
void cmd_put(int sock,int sockmsg,char* fileName)
{
write(sockmsg,user_cmd,sizeof(user_cmd));
write(sockmsg,cmd_arg,sizeof(cmd_arg));
int fd;
long fileSize;
int numRead;
char filePath[200];
struct stat fileSta;
memset(filePath,0,sizeof(filePath));
getcwd(filePath,sizeof(filePath));
strcat(filePath,"/");
strcat(filePath,fileName);
fd=open(filePath,O_RDONLY, S_IREAD);
if(fd!=-1)
{
fstat(fd,&fileSta);
fileSize=(long) fileSta.st_size;
write(sock,&fileSize,sizeof(long));
memset(buf,0,dataLen);
while(fileSize>dataLen)
{
read(fd,buf,dataLen);
write(sock,buf,dataLen);
fileSize=fileSize-dataLen;
}
read(fd,buf,fileSize);
write(sock,buf,fileSize);
close(fd);
printf("upload completed\n");
}
else
{
printf("open file %s failed\n",filePath);
}
}