Linux网络编程实现FTP服务器
介绍
FTP服务器(File Transfer Protocol Server)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务。 FTP是File Transfer Protocol(文件传输协议)。 程序运行,服务端不断接收客户端指令,服务端可同时处理多个客户端接入并对指令作出解析,并把执行结果返回给客户端,客户端根据服务端对指令的解析并把由服务端传递过来的处理信息通过客户端呈现给客户,实现文件的各种操作。
Linux网络编程实现的FTP服务器,服务器由服务端和客户端组成,具有浏览远程服务端的文件和浏览客户端本地文件,同时支持对远程服务端文件的删除,存储,归档操作处理,以及客户端对远程服务端文件的上传和下载。
要实现的功能:
利用socket实现云盘的:
ls———查看服务端文件
lls———查看客户端自己的文件
cd———切换服务端目录
lcd———切换客户端自己的目录
put———上传文件
get———下载文件
基本思路
服务端:
1:socket 创建服务端的套接字
2:bind 端口号和IP地址
3:listen 监听客户端的连接
4:accept 接受客户端的接入
5:read 接收客户端发送的message
6:服务端开始处理从客户端接收到的消息
7:send (write)服务端的msg到客户端
客户端:
1.socket 创建客户端的套接字,构建客户端和服务端发送和接收信息的桥梁
2.connect 连接上服务端
3.获取用户键盘输入,处理输入命令buf
4.send (write)客户端的command到服务端
5.read 服务端返回的message
客户端步骤1-4:
int main(int argc,char **argv)//指令行输入要连接服务端的IP地址和端口号
{int c_fd;struct sockaddr_in c_addr;int client;char Writebuf[128];char Readbuf[1024];if(argc != 3){perror("argc");exit(1);}//创建套接字c_fd = socket(AF_INET,SOCK_STREAM,0);if(c_fd == -1){perror("socket");exit(1);}memset(&c_addr,0,sizeof( struct sockaddr_in));c_addr.sin_family = AF_INET;c_addr.sin_port = htons(atoi(argv[2]));inet_aton(argv[1],&c_addr.sin_addr);//连接服务器client = sizeof(struct sockaddr_in);if(connect(c_fd,(struct sockaddr *)&c_addr,client)){perror("conncet");exit(1);}printf("connect success!\n");//发送和接收消息while(1){gets(Writebuf);//输入消息(指令)printf("cmd:%s\n",Writebuf);write(c_fd,Writebuf,strlen(Writebuf));//写入消息(指令)choosecmd(Writebuf,c_fd);//处理发送和接收的消息printf("--------------------cmd--------------------\n-");memset(Writebuf,0,strlen(Writebuf));}return 0;
}
服务端步骤1-5:
int main(int argc, char **argv)//指令行输入服务端IP地址和端口号
{int c_fd;int s_fd;int clen;struct sockaddr_in s_addr;struct sockaddr_in c_addr;int nread;char Readbuf[128];char Writebuf[128];//创建套接字s_fd = socket(AF_INET,SOCK_STREAM,0);if(s_fd == -1){perror("socket");exit(1);}if(argc != 3 ){perror("argc");exit(1);}memset(&s_addr,1,sizeof(struct sockaddr_in));s_addr.sin_family = AF_INET;s_addr.sin_port = htons(atoi(argv[2]));inet_aton(argv[1],&s_addr.sin_addr);//绑定端口号和ip地址bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//监听客户端的连接请求listen(s_fd,10);printf("waiting connect...\n");memset(&c_addr,0,sizeof(struct sockaddr_in));clen = sizeof(struct sockaddr_in);while(1){ //连接客户端c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);if(c_fd == -1){perror("accept");exit(1);}printf("%s connect success!\n",inet_ntoa(c_addr.sin_addr));//子进程接收客户端发送的消息if(fork() == 0){while(1){nread = read(c_fd,Readbuf,128);//调用处理消息函数choosecmd(Readbuf,c_fd);memset(Readbuf,0,sizeof(Readbuf));}}}return 0;
}
下面就是服务端和客户端处理消息的函数:
客户端步骤5:
//识别指令函数不同指令返回不同值给处理函数
int change(char cmd[128])
{if(!strcmp("lls",cmd)){return 1;}else if(!strcmp("ls",cmd)){return 2;}else if(!strcmp("g",cmd)){return 3;}else if(strstr(cmd,"lcd") != NULL){return 5;}else if(strstr(cmd,"cd") != NULL){return 4;}else if(strstr(cmd,"get") != NULL){return 6;}else if(strstr(cmd,"put") != NULL){return 7;}
}
//分割函数用于分割指令
char * getbind(char cmd[128])
{char *p;p = (char *)malloc(128);p = strtok(cmd," ");p = strtok(NULL," ");return p;
}
//获取文件处理函数
void getmessage(char cmd[128],int c_fd)
{char readbuf[8000];char *p = getbind(cmd);//得到要获取的文件名read(c_fd,readbuf,8000);//服务端把要获取的文件写入套接字这里进行读取int fd = open(p,O_RDWR|O_CREAT,0666);//打开该文件没有则创建write(fd,readbuf,strlen(readbuf));//写入文件内容printf("receive success!\n");close(fd);memset(p,0,8000);}
//存放文件处理函数
void putmessage(char cmd[128],int c_fd)
{int sfd;char *p = (char *)malloc(8000);char *readbuf = (char *)malloc(128);readbuf = getbind(cmd);//得到要存放的文件名if(access(readbuf,F_OK) == -1)//查找该文件{printf("NO file!\n");}else{sfd = open(readbuf,O_RDWR,0666);//打开该文件read(sfd,p,8000);//读取文件内容到pwrite(c_fd,p,strlen(p));把文件内容写给服务端close(sfd);//关闭文件memset(p,0,8000);}}
//指令处理函数
void choosecmd(char cmd[128],int c_fd)
{int ret = change(cmd);//把指令传给识别指令函数得到返回值printf("cmd is:%s,ret = %d\n",cmd,ret);char *p = (char *)malloc(8000);switch(ret){case 1://lls指令是查看客户端文件system("ls");//系统调用函数break;case 2://ls指令是查看服务端的文件read(c_fd,p,1024);//服务端把文件列表写入套接字,客户端读取套接字printf("%s\n",p);//打印服务端的文件memset(p,0,1024);break;case 3://g指令是退出服务printf("unconnecting\n");write(c_fd,"away host",128);close(c_fd);//关闭套接字exit(-1);//退出进程break;case 4://cd指令是改变服务端工作目录,这里客户端不需要操作printf("hello world!\n");break;case 5://lcd指令是改变客户端工作目录p = getbind(cmd);//调用分割函数得到要改变的目录chdir(p);//改变工作目录memset(p,0,sizeof(p));break;case 6://get指令是获取客户端文件getmessage(cmd,c_fd);//调用获取文件处理函数break;case 7://put指令是存放文件到服务端putmessage(cmd,c_fd);//调用存放文件处理函数break;}
服务端步骤6-7:
//识别指令函数
int change(char cmd[128])
{if(!strcmp("ls",cmd)){return 1;}else if(!strcmp("ps",cmd)){return 2;}else if(!strcmp("g",cmd)){return 3;}else if(strstr(cmd,"cd") != NULL){return 4;}else if(strstr(cmd,"get") != NULL){return 5;}else if(strstr(cmd,"put") != NULL){return 6;}
}
//分割函数得到指令后面的内容比如目录和文件名
char *getbehind(char cmd[128])
{char *p;p = (char *)malloc(128);p = strtok(cmd," ");p = strtok(NULL," ");return p;
}//客户端存放文件的处理函数
void putmessage(char cmd[128],int c_fd)
{char readbuf[8000];char *p = getbehind(cmd);//得到要存放的文件名read(c_fd,readbuf,8000);//读取文件内容int fd = open(p,O_RDWR|O_CREAT,0666);//打开该文件没有则创建write(fd,readbuf,strlen(readbuf));//把文件内容写入该文件printf("receive successful\n");close(fd);memset(readbuf,0,8000);}void choosecmd(char cmd[128],int c_fd)
{int ret;FILE *fdb;char *p = (char *)malloc(8000);char *readbuf = (char *)malloc(128);char freadbuf[128];int sfd;ret = change(cmd);//传入指令等待返回值switch(ret)//不同指令有不同返回值对应不同的处理{case 1://客户端要查看服务端的文件fdb = popen("ls","r");//把服务端的文件写入文件流fdbfread(freadbuf,sizeof(freadbuf),1,fdb);//再把文件流fdb的内容读到freadbufwrite(c_fd,freadbuf,sizeof(freadbuf));//把freadbuf内容写入套接字传给客户端memset(freadbuf,0,sizeof(freadbuf));//清空freadbufprintf("ok\n");break;case 2://查看服务端进程状态system("ps");break;case 3://退出服务read(c_fd,freadbuf,128);printf("%s\n",freadbuf);exit(1);break;case 4://改变服务端的工作目录p = getbehind(cmd);//要变成什么目录chdir(p);//改变工作目录memset(p,0,sizeof(p));break;case 5://客户端要获取文件readbuf = getbehind(cmd);//要获取什么文件if(access(readbuf,F_OK) == -1)//查找该文件{write(c_fd,"NO file",sizeof("NO file"));}else//如果有这个文件{sfd = open(readbuf,O_RDWR,0666);//打开文件read(sfd,p,8000);//把文件读到p里面去write(c_fd,p,strlen(p));//把文件写给客户端close(sfd);//关闭文件memset(p,0,8000);}break;case 6://客户端存放文件和case 5相似的处理只不过封装成了一个函数putmessage(cmd,c_fd);break;}
}
最终代码:
服务端:
#include <stdio.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>int change(char cmd[128])
{if(!strcmp("ls",cmd)){return 1;}else if(!strcmp("ps",cmd)){return 2;}else if(!strcmp("g",cmd)){return 3;}else if(strstr(cmd,"cd") != NULL){return 4;}else if(strstr(cmd,"get") != NULL){return 5;}else if(strstr(cmd,"put") != NULL){return 6;}
}char *getbehind(char cmd[128])
{char *p;p = (char *)malloc(128);p = strtok(cmd," ");p = strtok(NULL," ");return p;}void putmessage(char cmd[128],int c_fd)
{char readbuf[8000];char *p = getbehind(cmd);read(c_fd,readbuf,8000);int fd = open(p,O_RDWR|O_CREAT,0666);write(fd,readbuf,strlen(readbuf));printf("receive successful\n");close(fd);memset(readbuf,0,8000);}
void choosecmd(char cmd[128],int c_fd)
{int ret;FILE *fdb;char *p = (char *)malloc(8000);char *readbuf = (char *)malloc(128);char freadbuf[128];int sfd;ret = change(cmd);switch(ret){case 1:fdb = popen("ls","r");fread(freadbuf,sizeof(freadbuf),1,fdb);write(c_fd,freadbuf,sizeof(freadbuf));memset(freadbuf,0,sizeof(freadbuf));printf("ok\n");break;case 2:system("ps");break;case 3:read(c_fd,freadbuf,128);printf("%s\n",freadbuf);exit(1);break;case 4:p = getbehind(cmd);chdir(p);memset(p,0,sizeof(p));break;case 5:readbuf = getbehind(cmd);if(access(readbuf,F_OK) == -1){write(c_fd,"NO file",sizeof("NO file"));}else{sfd = open(readbuf,O_RDWR,0666);read(sfd,p,8000);write(c_fd,p,strlen(p));close(sfd);memset(p,0,8000);}break;case 6:putmessage(cmd,c_fd);break;}}
int main(int argc, char **argv)
{int c_fd;int s_fd;int clen;struct sockaddr_in s_addr;struct sockaddr_in c_addr;int nread;char Readbuf[128];char Writebuf[128];s_fd = socket(AF_INET,SOCK_STREAM,0);if(s_fd == -1){perror("socket");exit(1);}if(argc != 3 ){perror("argc");exit(1);}memset(&s_addr,1,sizeof(struct sockaddr_in));s_addr.sin_family = AF_INET;s_addr.sin_port = htons(atoi(argv[2]));inet_aton(argv[1],&s_addr.sin_addr);//bindbind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//listenlisten(s_fd,10);//acceptprintf("waiting connect...\n");memset(&c_addr,0,sizeof(struct sockaddr_in));clen = sizeof(struct sockaddr_in);while(1){c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);if(c_fd == -1){perror("accept");exit(1);}printf("%s connect success!\n",inet_ntoa(c_addr.sin_addr));//readif(fork() == 0){while(1){nread = read(c_fd,Readbuf,128);choosecmd(Readbuf,c_fd);memset(Readbuf,0,sizeof(Readbuf));}}}return 0;
}
客户端:
#include <stdio.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>int change(char cmd[128])
{if(!strcmp("lls",cmd)){return 1;}else if(!strcmp("ls",cmd)){return 2;}else if(!strcmp("g",cmd)){return 3;}else if(strstr(cmd,"lcd") != NULL){return 5;}else if(strstr(cmd,"cd") != NULL){return 4;}else if(strstr(cmd,"get") != NULL){return 6;}else if(strstr(cmd,"put") != NULL){return 7;}
}char * getbind(char cmd[128])
{char *p;p = (char *)malloc(128);p = strtok(cmd," ");p = strtok(NULL," ");return p;
}
void getmessage(char cmd[128],int c_fd)
{char readbuf[8000];char *p = getbind(cmd);read(c_fd,readbuf,8000);int fd = open(p,O_RDWR|O_CREAT,0666);write(fd,readbuf,strlen(readbuf));printf("receive success!\n");close(fd);memset(p,0,8000);}
void putmessage(char cmd[128],int c_fd)
{int sfd;char *p = (char *)malloc(8000);char *readbuf = (char *)malloc(128);readbuf = getbind(cmd);if(access(readbuf,F_OK) == -1){printf("NO file!\n");}else{sfd = open(readbuf,O_RDWR,0666);read(sfd,p,8000);write(c_fd,p,strlen(p));close(sfd);memset(p,0,8000);}}
void choosecmd(char cmd[128],int c_fd)
{int ret = change(cmd);printf("cmd is:%s,ret = %d\n",cmd,ret);char *p = (char *)malloc(8000);switch(ret){case 1:system("ls");break;case 2:read(c_fd,p,1024);printf("%s\n",p);memset(p,0,1024);break;case 3:printf("unconnecting\n");write(c_fd,"away host",128);close(c_fd);exit(-1);break;case 4:printf("hello world!\n");break;case 5:p = getbind(cmd);chdir(p);memset(p,0,sizeof(p));break;case 6:getmessage(cmd,c_fd);break;case 7:putmessage(cmd,c_fd);break;}}
int main(int argc,char **argv)
{int c_fd;struct sockaddr_in c_addr;int client;char Writebuf[128];char Readbuf[1024];if(argc != 3){perror("argc");exit(1);}c_fd = socket(AF_INET,SOCK_STREAM,0);if(c_fd == -1){perror("socket");exit(1);}memset(&c_addr,0,sizeof( struct sockaddr_in));c_addr.sin_family = AF_INET;c_addr.sin_port = htons(atoi(argv[2]));inet_aton(argv[1],&c_addr.sin_addr);//connectclient = sizeof(struct sockaddr_in);if(connect(c_fd,(struct sockaddr *)&c_addr,client)){perror("conncet");exit(1);}printf("connect ...\n");//write and sendwhile(1){//fgets(Writebuf,128,stdin); gets(Writebuf);printf("cmd:%s\n",Writebuf);write(c_fd,Writebuf,strlen(Writebuf));choosecmd(Writebuf,c_fd);printf("--------------------cmd--------------------\n-");memset(Writebuf,0,strlen(Writebuf));}return 0;
}
实现结果: