查看本机IP地址:
- 127.0.0.1
服务器功能:
- 可以获取服务器文件使用get指令
- 可以展示服务器有哪些文件使用ls指令
- 进入服务器某个文件夹使用指令cd+文件夹名称
- 上传本地文件到服务器,使用指令put
- pwd可以查看客户端在当前服务器的位置
客户端本地功能:
- lls查看客户端本地文件
- lcd+文件名,进入客户端某个文件
- lpwd可以查看当前客户端自己的路径
- help可查看服务器支持指令
- quit退出服务器
写代码的时候要写一个功能编译验证一下,不要把所有功能都写完后再编译验证,不容易调试。
简易FTP服务端代码:
#include<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>#define LS 0
#define PWD 1#define GET 2
#define PUT 3
#define CD 4
#define HELP 5
#define QUIT 6
#define OUT 7typedef struct Client
{char cmd[128];char databuf[1024];
}Cli,*Pcli;
char* getcmd(char* cmd)
{char* re=NULL;re=strtok(NULL," ");return re;
}
char* firstcmd(char* cmd)
{char*p;p=strtok(cmd," ");return p;
}
int changmsg(Pcli msg)
{char*cmd=firstcmd(msg->cmd);if(strcmp("ls",msg->cmd)==0) return LS;if(strcmp("pwd",msg->cmd)==0) return PWD;if(strcmp("help",msg->cmd)==0) return HELP;if(strcmp("quit",msg->cmd)==0) return QUIT;if(strcmp("get",cmd)==0) return GET;if(strcmp("put",cmd)==0) return PUT;if(strcmp("cd",cmd)==0) return CD;
}
int receHandle(int fd,Pcli msg)
{int ret;int size;int openfd;char* new;char newfilename[128];char* filename;FILE* file;ret=changmsg(msg);switch(ret){case PWD:case LS:file=popen(msg->cmd,"r");memset(msg,'\0',sizeof(Cli));fread(msg->databuf,1,1024,file);write(fd,msg,sizeof(Cli));fclose(file);break;case PUT:filename=getcmd(msg->cmd);openfd=open(filename,O_RDWR|O_CREAT,0660);printf("file has made\n");write(openfd,msg->databuf,strlen(msg->databuf));close(openfd);break;case GET:filename=getcmd(msg->cmd);if(access(filename,F_OK)==0){openfd=open(filename,O_RDWR);size=lseek(openfd,0,SEEK_END);lseek(openfd,0,SEEK_SET);memset(msg->databuf,'\0',1024);read(openfd,msg->databuf,size*sizeof(char));printf("send:%s\n",msg->databuf);write(fd,msg,sizeof(Cli));close(openfd);}else{memset(msg->cmd,'\0',128);strcpy(msg->cmd,"no");write(fd,msg,sizeof(Cli));}break;case CD:filename=getcmd(msg->cmd);sprintf(newfilename,"./%s",filename);if(access(newfilename,F_OK)==0){memset(msg->cmd,'\0',128);strcpy(msg->cmd,"yes");write(fd,msg,sizeof(Cli));chdir(newfilename);}else{memset(msg->cmd,'\0',128);strcpy(msg->cmd,"no");write(fd,msg,sizeof(Cli));}break;case HELP:memset(msg,'\0',sizeof(Cli));strcpy(msg->databuf,"cd\nlcd\nls\nlls\npwd\nlpwd\nput\nget\nhelp");write(fd,msg,sizeof(Cli));break;case QUIT:close(fd);return OUT;break;}
}int main()
{int bindre;int newfd;int re;int socketre;int listenre;pid_t fpid;Cli msg;struct sockaddr_in IP;struct sockaddr_in CLI;//客户端信息int len=sizeof(struct sockaddr_in);memset(&IP,'\0',len);memset(&CLI,'\0',len);IP.sin_family=AF_INET;IP.sin_port=htons(8686);IP.sin_addr.s_addr=inet_addr("192.168.1.198");socketre=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(socketre==-1){printf("create fail\n");perror("socket");exit(-1);}bindre=bind(socketre,(struct sockaddr*)&IP,len);if(bindre==-1){perror("bind");printf("bind fail\n");exit(-1);}listenre=listen(socketre,10);if(listenre==-1){printf("listen fail\n");perror("listen");exit(-1);}while(1){newfd=accept(socketre,(struct sockaddr*)&CLI,&len);if(newfd==-1){perror("accept");printf("accept fail\n");exit(-1);}printf("get client:%s\n",inet_ntoa(CLI.sin_addr));fpid=fork();if(fpid==0){while(1){memset(&msg,'\0',sizeof(Cli));if(read(newfd,&msg,sizeof(Cli))!=0){re=receHandle(newfd,&msg);if(re==OUT){printf("client is quit!\n");break;}}else {printf("Error! Don't connect!\n");break;}}}if(fpid>0){waitpid(fpid,NULL,WNOHANG | WUNTRACED);}}return 0;
}
服务端代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#define LS 0
#define PWD 1
#define GET 2
#define PUT 3
#define CD 4
#define HELP 5
#define NO 6
#define LCD 7
#define LLS 8
#define LPWD 9
#define QUIT 10
#define OUT 11
typedef struct Client
{char cmd[128];char databuf[1024];
}Cli,*Pcli;
char* getcmd(char* cmd)
{char* p;p=strtok(cmd," ");return p;
}
int changmsg(Pcli snd)
{char* cmd=firstcmd(snd->cmd);if(strcmp("lls",snd->cmd)==0) return LLS;if(strcmp("quit",snd->cmd)==0) return QUIT;if(strcmp("ls",snd->cmd)==0) return LS;if(strcmp("pwd",snd->cmd)==0) return PWD;if(strcmp("quit",snd->cmd)==0) return QUIT;if(strcmp("lpwd",snd->cmd)==0) return LPWD;if(strcmp("help",snd->cmd)==0) return HELP;if(strcmp(cmd,"get")==0) return GET;if(strcmp(cmd,"put")==0) return PUT;if(strcmp(cmd,"cd")==0) return CD;if(strcmp(cmd,"lcd")==0) return LCD;return NO;
}
int client_Handle(int fd,Pcli snd)
{int ret;int openfd;int size;char newcmd[128];char* filename;strcpy(newcmd,snd->cmd);ret=changmsg(snd);switch(ret){case LLS:printf("---------------------------------------------------------");putchar('\n');system("ls");putchar('\n');printf("---------------------------------------------------------\n");break;case LPWD:printf("---------------------------------------------------------");putchar('\n');system("pwd");putchar('\n');printf("---------------------------------------------------------\n");break;case PWD:case LS:case HELP:write(fd,snd,sizeof(Cli));read(fd,snd,sizeof(Cli));printf("---------------------------------------------------------");putchar('\n');printf("%s",snd->databuf);putchar('\n');printf("---------------------------------------------------------\n");memset(snd,'\0',sizeof(Cli));break;case PUT:filename=getcmd(snd->cmd);if(access(filename,F_OK)==0){openfd=open(filename,O_RDWR);size=lseek(openfd,0,SEEK_END);lseek(openfd,0,SEEK_SET);memset(snd->databuf,'\0',1024);read(openfd,snd->databuf,sizeof(char)*size);memset(snd->cmd,'\0',128);strcpy(snd->cmd,newcmd);write(fd,snd,sizeof(Cli));close(openfd);}else{printf("文件不存在\n");}break;case GET:filename=getcmd(snd->cmd);strcpy(snd->cmd,newcmd);write(fd,snd,sizeof(Cli));memset(snd->databuf,'\0',1024);read(fd,snd,sizeof(Cli));if(strcmp(snd->cmd,"no")==0){printf("No This File!\n");}else{openfd=open(filename,O_RDWR|O_CREAT,0660);write(openfd,snd->databuf,strlen(snd->databuf));close(openfd);}break;case CD:memset(snd->cmd,'\0',128);strcpy(snd->cmd,newcmd);write(fd,snd,sizeof(Cli));memset(snd->cmd,'\0',128);read(fd,snd,sizeof(Cli));if(strcmp(snd->cmd,"no")==0){printf("File isn't exist!\n");}else{printf("get:%s\n",snd->cmd);}break;case LCD:filename=getcmd(snd->cmd);if(access(filename,F_OK)==0){chdir(filename);}else{printf("Under the path,dont't have this file!\n");}break;case NO:printf("command isn't exist.\n");break;case QUIT:strcpy(snd->cmd,"quit");write(fd,snd,sizeof(Cli));close(fd);return OUT;break;}
}
int main()
{int socketfd;int conre;int handre;char cmd[128];char*writebuf;char*readbuf;char mark[128];Cli sendmsgr;struct Client CL;struct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(8686);addr.sin_addr.s_addr=inet_addr("192.168.1.198");socketfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(socketfd==-1){printf("socket create fail\n");perror("socket");exit(-1);}conre=connect(socketfd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in));if(conre==-1){printf("connect fail\n");perror("connect");exit(-1);}printf("hanve conected server...\n");while(1){memset(&sendmsgr,'\0',sizeof(Cli));printf(">");fgets(cmd,128,stdin);strncpy(sendmsgr.cmd,cmd,strlen(cmd)-1);printf("cmd:%s\n",sendmsgr.cmd);handre=client_Handle(socketfd,&sendmsgr);if(handre==OUT){printf("server is quit!\n");exit(0);}}return 0;
}
学习体会补充:
- read是有返回值n的,如果n>0,那么就可以读到BUF里去,n=0,说明客户端发送了FIN信号,就断开连接,n<0,说明发生了中断或者错误。
- 学习到新的函数chdir和access的用法,更加深入的了解socket网络编程函数的使用,巩固了之前文件系统那里学习到的函数,对结构体和指针的使用更加熟练,总的来说,代码不难但是第一次那么长的代码,还是有点小难度的,只要注意客户端和服务端传递参数的时候要保证发送和接收的类型一样就好,这里我就用了结构体来存放发送的信息,那么接收也要用结构体,注意初始化,还有就是write的时候最好有多少东西就写多少东西不然内容后面会有很多乱码,chdir函数在服务器端我用了相对地址,直接用文件名不行(没有找到原因),还有就是这个服务端接入一个客户端还好,但是接入多个客户端就不知道要把信息发给谁(这个问题没有处理)。
- 如果后面后时间的话,还想为服务器增添一些登录验证的功能,用链表存内每个用户的信息,用户注册可以插入链表,用户注销可以删掉链表,管理员还可以查找用户信息等等功能,看看现在学习到的东西还很少,还要努力呀!!