/*
*本程序参考rfc959标准。能与遵守此标准的服务器进行信息交互。仅限于windows系统。
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>/*system()*/
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#define ONUM 512
#define MNUM 512
#define FNUM 512
#define pt
struct host
{
char ip[20];
unsigned short port;
};
SOCKET ts;
fd_set readfds;
struct timeval timeval;
struct host host;
char renum[4];
char ordertemp[ONUM];
char order[ONUM];
char ordercp[ONUM];
char mess[MNUM];
char file[FNUM];
char setpath[FNUM];
char setpathf[FNUM];
int i,door,r,sys,seti;/*i for;door switch;r receive num;sys system state;set set state*/
char *p;/*strtok*/
int printmess();
void input(char ordertemp[]);
int ftp();
int user();
int pass();
int command();
int list();
SOCKET createDataSocket();
int set();
int retr();
int stor();
int stor()
{
char filename[256];
SOCKET ds;
int wi;
int r2,r3,r4,bsnum,brnum;
FILE *fp=NULL;
set();
memset(filename,'\0',256);
memset(order,'\0',ONUM);
for(i=5;i<=200&&ordercp[i]!='\0';i++)order[i-5]=ordercp[i];
strcpy(filename,setpathf);
strcat(filename,"\\\\");
strcat(filename,order);
memset(order,'\0',ONUM);
strcpy(order,"type i\r\n");/*type i 二进制 type a ASCII*/
send(ts,order,strlen(order),0);
switch(printmess())
{
case 421:closesocket(ts);sys=0;return 421;
case 530:closesocket(ts);sys=0;return -1;
case 500:
case 501:
case 504:
case 226:return -1;
case 200:break;
default:return -1;
}
ds=createDataSocket();
if(ds==-1)return -1;
strcat(ordercp,"\r\n");
send(ts,ordercp,strlen(ordercp),0);
switch(printmess())
{
case 421:closesocket(ds);closesocket(ts);sys=0;return 421;
case 532:
case 530:closesocket(ds);closesocket(ts);sys=0;return -1;
case 450:
case 452:
case 553:
case 500:
case 501:closesocket(ds);return -1;
case 125:
case 150:break;
default:closesocket(ds);return -1;
}
fp=fopen(filename,"rb");
if(!fp){printf("read file fail!\n");closesocket(ds);return -1;}
r2=0;r3=0;r4=0;bsnum=0;brnum=0;wi=1;
while(wi)
{
memset(file,'\0',FNUM);
r=fread(file,sizeof(char),FNUM,fp);
if(r==0){closesocket(ds);wi=0;break;}
brnum=brnum+r;
r3=r;
printf("read %8d bytes! have read %16d bytes!\r",r,brnum);
do
{
r2=send(ds,file,r3,0);
if(r2==SOCKET_ERROR){printf("send file error!");closesocket(ds);return -1;}
bsnum=bsnum+r2;
r3=r3-r2;
printf("send %8d bytes! have sended %16d bytes!\r",r2,bsnum);
}while(brnum>bsnum);
}/*while*/
printf("\n");
switch(printmess())
{
case 425:
case 426:
case 451:
case 551:
case 552:closesocket(ds);fclose(fp);return -1;
case 250:
case 226:fclose(fp);return 0;
default:return 0;
}
}/*stor*/
int retr()
{
char filename[256];
unsigned long fsize,wfsize;
int r2,wi;
SOCKET ds;
FILE *fp=NULL;
memset(filename,'\0',256);
memset(order,'\0',ONUM);
for(i=5;i<=200&&ordercp[i]!='\0';i++)order[i-5]=ordercp[i];
strcpy(filename,setpathf);
strcat(filename,"\\\\");
strcat(filename,order);
ds=createDataSocket();
if(ds==-1)return -1;
memset(order,'\0',ONUM);
strcpy(order,"type i\r\n");/*type i 二进制 type a ASCII*/
send(ts,order,strlen(order),0);
switch(printmess())
{
case 421:closesocket(ds);closesocket(ts);sys=0;return 421;
case 530:closesocket(ds);closesocket(ts);sys=0;return -1;
case 500:
case 501:
case 504:
case 226:closesocket(ds);return -1;
case 200:break;
default:closesocket(ds);return -1;
}
strcat(ordercp,"\r\n");
send(ts,ordercp,strlen(ordercp),0);
switch(printmess())
{
case 421:closesocket(ds);closesocket(ts);sys=0;return 421;
case 530:closesocket(ds);closesocket(ts);sys=0;return -1;
case 450:
case 500:
case 501:
case 550:closesocket(ds);return -1;
case 125:
case 150:break;
default:closesocket(ds);return -1;
}
set();
system(setpath);
fp=fopen(filename,"wb");
if(!fp){printf("create file fail!\n");closesocket(ds);printmess();return -1;}
wi=1;fsize=0;wfsize=0;
while(wi)
{
memset(file,'\0',FNUM);
r=recv(ds,file,FNUM,0);
if(r==SOCKET_ERROR)
{
printf("file recv error!\n");
closesocket(ds);
fclose(fp);
return -1;
}
fsize=fsize+r;
if(r==0){wi=0;break;}
printf("receive %8d bytes! have received %16d bytes!\r",r,fsize);
r2=fwrite(file,sizeof(char),r,fp);
// fflush(fp);/*这里是关键*/
wfsize=wfsize+r2;
printf("write %8d bytes!have written %20d bytes!\r",r2,wfsize);
}/*while*/
printf("\n");
fflush(fp);/*这里是关键*/
switch(printmess())
{
case 425:
case 426:
case 451:closesocket(ds);fclose(fp);return -1;
case 250:
case 226:
closesocket(ds);
wi=1;
while(wi)if(fclose(fp)==0)wi=0;return 0;
default:closesocket(ds);fclose(fp);return 0;
}
}/*retr()*/
int set()
{
int n,m;
n=3;m=0;
if(strcmp(order,"set")!=0&&seti==1)return 1;
else if(strcmp(order,"set")!=0&&seti==0)
{
memset(setpath,'\0',FNUM);
memset(setpathf,'\0',FNUM);
strcpy(setpath,"md d:\\rhFTPdir");
strcpy(setpathf,"d:\\\\rhFTPdir");
return 2;
}
memset(setpath,'\0',FNUM);
memset(setpathf,'\0',FNUM);
memset(order,'\0',ONUM);
if(ordercp[5]!=':'){printf("error input!\n");return-1;}
for(i=4;i<=200&&ordercp[i]!='\0';i++)order[i-4]=ordercp[i];
strcpy(setpath,"md ");
for(i=0;i<=FNUM-5&&order[i]!='\0';i++)
{
if(order[i]=='\\'){strcat(setpath,"\\\\");n++;strcat(setpathf,"\\\\");m++;continue;}
setpathf[i+m]=order[i];
setpath[i+n]=order[i];
}
printf("setpath %s\n",setpath);
seti=1;
return 0;
}/*set*/
int list()
{
SOCKET ds;
int wi;
ds=createDataSocket();
if(ds==-1)return -1;
strcat(ordercp,"\r\n");
send(ts,ordercp,strlen(ordercp),0);
switch(printmess())
{
case 421:closesocket(ds);closesocket(ts);sys=0;return 421;
case 530:closesocket(ds);closesocket(ts);sys=0;return -1;
case 450:
case 500:
case 501:
case 502:closesocket(ds);return -1;
case 125:
case 150:break;
default:closesocket(ds);return -1;
}
wi=1;
while(wi)
{
memset(file,'\0',FNUM);
r=recv(ds,file,FNUM-1,0);
if(r==SOCKET_ERROR){printf("list file recv error!\n");closesocket(ds);return -1;}
printf("%s",file);
if(r==0)wi=0;
}
switch(printmess())
{
case 425:
case 426:
case 451:
case 226:
case 250:closesocket(ds);return 0;
default:closesocket(ds);return -1;
}
}/*list*/
SOCKET createDataSocket()
{
char p1[5],p2[5];
unsigned short port;
int p1s,p2s;
SOCKET ds;
struct sockaddr_in server;
memset(order,'\0',ONUM);/*pasv*/
strcpy(order,"pasv\r\n");
send(ts,order,strlen(order),0);
r=printmess();
if(r==-1||r!=227)return -1;
memset(p1,'\0',5);
memset(p2,'\0',5);
p1s=0;p2s=0;
for(i=0,r=0;i<200&&mess[i]!='\0';i++)
{
if(mess[i]==','){r++;continue;}
if(r==4){p1[p1s]=mess[i];p1s++;continue;}
if(r==5){p2[p2s]=mess[i];p2s++;continue;}
}
port=atoi(p1)*256+atoi(p2);
printf("port:%d\n",port);
server.sin_family=AF_INET;
server.sin_port=htons(port);
server.sin_addr.S_un.S_addr=inet_addr(host.ip);
ds=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);/*TCP*/
if(ds==-1){printf("Failed socket() in createDataSocket()\n");return -1;}
r=connect(ds,(struct sockaddr *)&server,sizeof(server));
if(r==SOCKET_ERROR){printf("connect error in createDataSocket()!\n");closesocket(ds);return -1;}
return ds;
}/*createDataSocket()*/
int command()
{
strcat(ordercp,"\r\n");
send(ts,ordercp,strlen(ordercp),0);
switch(printmess())
{
case 421:closesocket(ts);sys=0;return 421;
case 221:closesocket(ts);sys=0;return 221;
case 530:closesocket(ts);sys=0;return 0;
case 200:
case 250:
case 450:
case 550:
case 500:
case 501:
case 502:return 0;
default:return -1;
}
}/*command*/
int pass()
{
strcat(ordercp,"\r\n");
send(ts,ordercp,strlen(ordercp),0);
switch(printmess())
{
case 421:closesocket(ts);sys=0;return 421;
case 530:closesocket(ts);sys=0;return 0;
case 500:
case 501:
case 503:
case 202:return 0;
case 332:sys=1;return 0;
case 230:sys=3;return 0;
default:return -1;
}
}/*pass*/
int user()
{
if(ordercp[5]=='-'){strcat(order," anonymous\r\n");send(ts,order,strlen(order),0);}
else {strcat(ordercp,"\r\n");send(ts,ordercp,strlen(ordercp),0);}
switch(printmess())
{
case 421:closesocket(ts);sys=0;return 421;
case 530:closesocket(ts);sys=0;return 0;
case 230:sys=3;return 0;
case 500:
case 501:
case 332:return 0;
case 331:sys=2;return 0;
default:return -1;
}
}/*user*/
int ftp()
{
WSADATA wsaData;
struct sockaddr_in serveraddr;
if(sys!=0){printf("please bye first!\n");return 0;}
WSAStartup(MAKEWORD(2,2),&wsaData);/*建立与Socket库绑定*/
ts=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);/*TCP*/
if(ts==-1)
{
printf("Failed socket()\n");
WSACleanup();
return -1;
}
memset(host.ip,'\0',20);
p=strtok(NULL," ");
strcpy(host.ip,p);
p=strtok(NULL," ");
if(p==NULL)host.port=21;
else host.port=atoi(p);
serveraddr.sin_family=AF_INET;/*主机地址标识*/
serveraddr.sin_port=htons(host.port);/*port htons 16*/
serveraddr.sin_addr.S_un.S_addr=inet_addr(host.ip);/*ip*/
r=connect(ts, (struct sockaddr *)&serveraddr, sizeof(serveraddr));/*发送连接请求*/
if(r==SOCKET_ERROR){printf("connect error!\n");return -1;}
switch(printmess())
{
case 220:sys=1;return 0;
case 120:while(printmess()==220){sys=1;return 0;}
case 421:closesocket(ts);sys=0;return 421;
case -1:return -1;
default:return -1;
}
}/*ftp*/
int printmess()
{
int p,n,wi;
p=0;n=0;wi=1;
memset(renum,'\0',4);
FD_ZERO(&readfds);/*select*/
FD_SET(ts,&readfds);
r=select(0,&readfds,NULL,NULL,&timeval);
while(r>0&&FD_ISSET(ts, &readfds)&&wi==1)
{
memset(mess,'\0',MNUM);
r=recv(ts,mess,MNUM-1,0);
if(r==SOCKET_ERROR){printf("printmess recv error!\n");return -1;}
if(p==0){strncpy(renum,mess,4);n=atoi(renum);p=1;}
printf("%s",mess);
FD_ZERO(&readfds);/*select*/
FD_SET(ts,&readfds);
r=select(0,&readfds,NULL,NULL,&timeval);
if(r==0)wi=0;
}
return n;
}/*printmess()*/
void input(char ordertemp[])
{
for(i=0;i<ONUM;i++)
{
ordertemp[i]=getchar();
if(ordertemp[i]==10){ordertemp[i]='\0';break;}/*10 enter*/
}
if(ordertemp[0]!='\0')
{
strcpy(ordercp,ordertemp);
p=NULL;
p=strtok(ordertemp," ");
strcpy(order,p);
strlwr(order);
}
}/*input*/
int main()
{
int wi;
seti=0;
timeval.tv_sec=0;/*5000ms 避免死锁*/
timeval.tv_usec=500000;
printf("** Welcome to use RedHaw FTPclient! **\n");
sys=0;/*0-初始 1-接收user 2-接收pass 3-接收其他command*/
wi=1;
while(wi)
{
memset(ordertemp,'\0',ONUM);
memset(order,'\0',ONUM);
memset(ordercp,'\0',ONUM);
switch(sys)
{
case 0:printf("+ ftp <host-ip> [port] + exit +\n");break;
case 1:printf("+ user <username> Tip:\" \'-\' for anonymous \" +\n");break;
case 2:printf("+ pass <password> Tip:\" \'-\' for anonymous \" +\n");break;
default:printf("+ help|list|cdup|cwd <dir>|mkd <>|rmd <>|set <dir> +\n");
printf("+ user|quit|exit|retr <down>|stor <up>|dele <file> +\n");
}
printf("rhFTP>");
input(ordertemp);
if(ordertemp[0]=='\0')continue;
if(strcmp(order,"ftp")==0&&sys==0)door=1; /*1 ftp */
else if(strcmp(order,"user")==0&&(sys==1||sys==3))door=2; /*2 user*/
else if(strcmp(order,"pass")==0&&sys==2)door=3; /*3 pass*/
else if(strcmp(order,"quit")==0&&sys==3)door=4; /*4 quit*/
else if(strcmp(order,"exit")==0&&(sys==0||sys==3))door=5; /*5 exit*/
else if(strcmp(order,"list")==0&&sys==3)door=6; /*6 list*/
else if(strcmp(order,"cwd")==0&&sys==3)door=7; /*7 cwd */
else if(strcmp(order,"dele")==0&&sys==3)door=8; /*8 dele*/
else if(strcmp(order,"retr")==0&&sys==3)door=9; /*9 retr*/
else if(strcmp(order,"set")==0&&sys==3)door=10; /*10 set */
else if(strcmp(order,"stor")==0&&sys==3)door=11; /*11 stor*/
else if(strcmp(order,"cdup")==0&&sys==3)door=12; /*12 cdup*/
else if(strcmp(order,"help")==0&&sys==3)door=13; /*13 help*/
else if(strcmp(order,"mkd")==0&&sys==3)door=14; /*14 mkd */
else if(strcmp(order,"rmd")==0&&sys==3)door=15; /*15 rmd */
else door=0;
switch(door)
{
case 0:printf("Disallowed command!\n");break;
case 1:r=ftp();break;
case 2:r=user();break;
case 3:r=pass();break;
case 4:r=command();break;
case 5:if(sys==3){memset(ordercp,'\0',ONUM);strcpy(ordercp,"quit\r\n");
command();closesocket(ts);}wi=0;break;
case 13:
case 6:r=list();break;
case 12:
case 14:
case 15:
case 7:
case 8:r=command();break;
case 9:r=retr();break;
case 10:r=set();break;
case 11:r=stor();break;
default:wi=0;break;
}/*switch(door)*/
}/*while(wi)*/
WSACleanup();
return 0;
}/*main*/
这是计算机网络课程设计的作品,简单实现了FTP客户端。
用winsock2头文件。算是socket编程的学习实践。
所有代码在vc6.0下调试通过。