使用epoll方法,用c/c++实现一个FTP服务器

Posted Madao东治

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用epoll方法,用c/c++实现一个FTP服务器相关的知识,希望对你有一定的参考价值。

先贴个代码上来,晚点补全教程

编译环境:ubuntu16.04

编译命令(先编译执行服务端):g++ serv.cpp -o serv.out

              ./serv.out

      客户端:g++ client.cpp -o serv.cpp

        ./client.out

 

可以实现三种命令:get <filename>获取服务端文件夹内指定文件

          ls 获取文件列表

          quit 退出

 

服务端代码:

  1 #include<iostream>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<errno.h>
  5 #include<sys/socket.h>
  6 #include<arpa/inet.h>
  7 #include<sys/epoll.h>
  8 #include<string.h>
  9 #include<fcntl.h>
 10 #include<cstdio>
 11 using namespace std;
 12 
 13 #define SER_IP "127.0.0.1"
 14 
 15 // server port
 16 #define SER_PORT 8860
 17 
 18 //epoll size
 19 
 20 #define EPOLL_SIZE 0xFFFF
 21 #define BUF_SIZ 0xFFFF
 22 #define BUF_SIZE 0xFFFF
 23 
 24 void ErrorHandling(string message){
 25     
 26     cout<<message<<endl;
 27     system("pause");
 28     exit(-1);
 29 }
 30 /*设置epoll为边缘触发模式*/
 31 void setnoblockingmode(int fd){
 32 
 33     fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0)|O_NONBLOCK);
 34 
 35 }
 36 
 37 bool close_connection(int epfd,int cnlt_socket)
 38 
 39 {
 40 
 41     cout<<"client "<<cnlt_socket<<"disconnected"<<endl;
 42     close(cnlt_socket);
 43     epoll_ctl(epfd,EPOLL_CTL_DEL,cnlt_socket,NULL);
 44     cout<<"close done!"<<endl;
 45 
 46 }
 47 
 48 bool send_file(int cnlt_socket,char *file_name,int epfd)
 49 {
 50 
 51     FILE* fd = NULL;
 52     char data[BUF_SIZE];
 53     size_t num_read;                                    
 54     fd = fopen(file_name, "r"); // 打开文件
 55     cout<<"file_name is"<<file_name<<endl;
 56     if (!fd){
 57         char send_error[BUF_SIZE];
 58         sprintf(send_error,"550");
 59         send(cnlt_socket,send_error,BUF_SIZE,0);
 60         close_connection(epfd,cnlt_socket); 
 61     }
 62     else
 63         {    
 64             cout<<"file open successful"<<endl; ; 
 65             do 
 66             {
 67                 num_read = fread(data, 1, BUF_SIZE, fd); // 读文件内容
 68                 if (num_read < 0) 
 69                 printf("error in fread()\\n");
 70 
 71                 if (send(cnlt_socket, data, num_read, 0) < 0) // 发送数据(文件内容)
 72                 perror("error sending file\\n");
 73 
 74             }while (num_read > 0);    
 75             cout<<"transfer done!closing socket"<<endl;
 76             close(cnlt_socket);
 77             cout<<"closing done!"<<endl;
 78         }
 79 }
 80 
 81 
 82 int main()
 83 {
 84     char tempbuffer[BUF_SIZE];
 85     int serversocket,clientsocket;
 86     struct sockaddr_in seraddr,clientaddr;
 87     seraddr.sin_family=PF_INET;
 88     seraddr.sin_port=htons(SER_PORT);
 89     seraddr.sin_addr.s_addr=inet_addr(SER_IP);
 90     char message[BUF_SIZ]="connected";
 91     char buffer[BUF_SIZ];
 92     char *copy_buffer;
 93     memset(buffer,0,sizeof(buffer));
 94      
 95     serversocket=socket(PF_INET,SOCK_STREAM,0);
 96 
 97     if(bind(serversocket,(struct sockaddr*)&seraddr,sizeof(seraddr))==-1)
 98          perror("connect error");
 99 
100     if(listen(serversocket,5)==-1)
101         perror("listen Error");
102     /*注册epoll*/
103     int epfd,event_cnt;
104     epfd = epoll_create(EPOLL_SIZE);
105     struct epoll_event ep_event[EPOLL_SIZE];
106     struct epoll_event event;
107     event.events=EPOLLIN;
108     event.data.fd=serversocket;
109     epoll_ctl(epfd,EPOLL_CTL_ADD,serversocket,&event);
110 
111     while(1)
112     {
113 
114         event_cnt=epoll_wait(epfd,ep_event,EPOLL_SIZE,-1);
115 
116         if(event_cnt==-1)
117         {
118             perror("epoll_wait error");
119             exit(-1);
120         }
121 
122         for(int i=0;i<event_cnt;i++)
123         {
124             
125             if(ep_event[i].data.fd==serversocket)
126             {
127 
128                 socklen_t clientsize;
129 
130                 clientsocket=accept(serversocket,(struct sockaddr *)&clientaddr,&clientsize);
131 
132                 if(clientsocket==-1)
133                 ErrorHandling("accept Error");
134                 else
135                 {
136 
137                     setnoblockingmode(clientsocket);
138                     event.events=EPOLLIN|EPOLLET;
139                     event.data.fd=clientsocket;
140                     epoll_ctl(epfd,EPOLL_CTL_ADD,clientsocket,&event);
141 
142                      cout<<"fd added to epoll!"<<endl;
143                      cout<<clientsocket<<"connected"<<endl;
144                 }
145             }
146             
147             else{
148                 
149                     int strlen=read(ep_event[i].data.fd,buffer,BUF_SIZE);
150 
151                     if(strlen==0)
152                     {
153                         
154                         close_connection(epfd,ep_event[i].data.fd);
155                         break;
156 
157                     }else if(strlen<0)
158                     {
159 
160                         cout<<"strlen error"<<endl;
161 
162                     }
163                     else 
164                     {
165                         char m_copy[BUF_SIZE];
166                         sprintf(m_copy,buffer);
167                         copy_buffer=strtok(buffer," ");
168 
169                         if(strcmp(copy_buffer,"ls") == 0)
170                         {
171                             /*使用系统命令获取文件清单*/
172                             system("ls >temp.txt");
173 
174                             send_file(ep_event[i].data.fd,"temp.txt",epfd);    
175                             close_connection(epfd,ep_event[i].data.fd);            
176 
177                         }else if(strcmp(copy_buffer,"quit") == 0)
178                         
179                         {
180 
181                         close_connection(epfd,ep_event[i].data.fd);
182                         
183                         }
184                         else if(strcmp(copy_buffer,"get")==0)
185                         {
186                         
187                         copy_buffer=strtok(m_copy," ");                        
188                         copy_buffer=strtok(NULL," ");
189                         cout<<"file name is: "<<copy_buffer<<endl;
190                         send_file(ep_event[i].data.fd,copy_buffer,epfd);
191 
192                         }else
193                             close_connection(epfd,ep_event[i].data.fd);
194                     }
195                 }
196         }
197     }
198 
199 close(serversocket);
200 close(epfd);
201 
202 return(0);
203 }
View Code

客户端代码:

  1 /*write by hakase 2016.12*/
  2 #include<iostream>
  3 #include<stdlib.h>
  4 #include<unistd.h>
  5 #include<errno.h>
  6 #include<sys/socket.h>
  7 #include<arpa/inet.h>
  8 #include<sys/epoll.h>
  9 #include<string.h>
 10 #include<fcntl.h>
 11 #include<cstdio>
 12 using namespace std;
 13 
 14 #define SER_PORT 8860
 15 #define SER_IP "127.0.0.1"
 16 
 17 #define EPOLL_SIZE 0xFFFF
 18 #define BUF_SIZE 0xFFFF
 19 #define GET_FILE "get %s"
 20 
 21 void ErrorHandling(string message){
 22     
 23     cout<<message<<endl;
 24     system("pause");
 25     exit(-1);
 26 }
 27 
 28 int main(){
 29 
 30     int ser_socket;
 31     struct sockaddr_in seraddr;
 32     char message[BUF_SIZE];
 33     char send_message[BUF_SIZE];
 34     bzero(message,0);
 35     char q_message[BUF_SIZE];
 36     sprintf(q_message,"quit");    
 37     
 38     /*设置服务器地址*/
 39     seraddr.sin_family=PF_INET;    
 40     seraddr.sin_port=htons(SER_PORT);
 41     seraddr.sin_addr.s_addr=inet_addr(SER_IP);
 42     
 43     /*创建服务端套接字*/
 44     ser_socket=socket(PF_INET,SOCK_STREAM,0);
 45         if(ser_socket < 0) { perror("sock error"); exit(-1); }
 46 
 47 
 48     if(connect(ser_socket, (struct sockaddr *)&seraddr, sizeof(seraddr)) < 0) {
 49         perror("connect error");
 50         exit(-1);
 51         }
 52     else {
 53         cout<<"connect!"<<endl;
 54 
 55         int test_flag=1;
 56 
 57         if(test_flag==1){
 58             char data[BUF_SIZE];
 59             int size;
 60             char file_name[BUF_SIZE];
 61             char input[BUF_SIZE];
 62             
 63             /*获取用户的指令*/
 64             gets(file_name);
 65 
 66             /*用于拆分命令的空格行时使用临时空间储存被拆分的命令*/
 67             char *copy_buffer=(char *)malloc(sizeof(char)*100);
 68             char *m_copy2=(char *)malloc(sizeof(char)*100);
 69             
 70             sprintf(m_copy2,file_name);
 71             
 72             /*拆分命令*/
 73             copy_buffer=strtok(m_copy2," ");
 74             cout<<"request oder is:"<<copy_buffer<<endl;
 75 
 76             /*如果是获取文件清单命令*/
 77             if(strcmp(copy_buffer,"ls")==0){
 78                 cout<<"enter ls"<<endl;
 79                 char temp_data[BUF_SIZE];
 80                 
 81                 /*本地建立临时文件,并且从服务端获取文件列表*/
 82                 FILE* fd = fopen("temp.txt", "rt+");
 83                 send(ser_socket,copy_buffer,BUF_SIZE,0);
 84                 
 85                 while ((size = read(ser_socket, data, BUF_SIZE)) > 0) 
 86                     fwrite(data, 1, size, fd);
 87 
 88                 size_t numb_read=1;
 89                 do{
 90                     numb_read=fread(temp_data,1,BUF_SIZE,fd);
 91                         if (numb_read < 0) 
 92                             printf("error in fread()\\n");
 93                     }while(numb_read>0);
 94 
 95                 cout<<temp_data<<endl;                
 96                 cout<<"done!"<<endl;
 97                 close(ser_socket);
 98                 return(0);
 99 
100             }
101             /*如果是退出命令,则直接退出*/
102             else if(strcmp(copy_buffer,"quit")==0){
103                 send(ser_socket,copy_buffer,BUF_SIZE,0);
104                 close(ser_socket);
105                 return(0);
106             }
107             /*如果是获取命令,则拆分命令,获得后半部分的文件名字*/
108             else if(strcmp(copy_buffer,"get")==0){
109 
110                 char check[100];
111                 size_t check_lenth;
112                 copy_buffer=strtok(file_name," ");
113                 copy_buffer=strtok(NULL," ");
114             FILE* fd = fopen(copy_buffer, "w"); 
115             sprintf(send_message,"get %s",copy_buffer);
116             //cout<<"send_message is :"<<send_message<<"aaaa"<<endl;
117             send(ser_socket,send_message,BUF_SIZE,0);
118             
119             /*在传输文件前,需要先向服务端询问是否存在该文件*/
120             check_lenth = recv(ser_socket,check,BUF_SIZE,0);
121             /*如果不存在该文件,则转告用户*/
122             if(strcmp(check,"550")==0){
123                 cout<<"didn\'t find file named "<<copy_buffer<<endl;
124                 close(ser_socket);
125                 return(0);
126             }
127     /* 将服务器传来的数据(文件内容)写入本地建立的文件 */
128             while ((size = recv(ser_socket, data, BUF_SIZE, 0)) > 0) 
129             fwrite(data, 1, size, fd);
130 
131             cout<<"data transfer success"<<endl;
132 
133             close(ser_socket);
134             fclose(fd);
135 
136                 return(0);
137             }else{
138                 /*命令不符合要求*/
139                 cout<<"wrong request"<<endl;
140                 send(ser_socket,q_message,BUF_SIZE,0);
141                 close(ser_socket);
142                 return(0);
143             }
144         }
145     }
146     close(ser_socket);
147     return(0); 
148 }
View Code

 

以上是关于使用epoll方法,用c/c++实现一个FTP服务器的主要内容,如果未能解决你的问题,请参考以下文章

适合新手练手的免费C/C++小程序

c#C/S实现文件的上传下载

通过十个问题助你彻底理解linux epoll工作原理

6种epoll的做法,从redis,memcached到nginx的网络模型实现

用Linux / C实现基于自动扩/减容线程池+epoll反应堆检测沉寂用户模型的服务器框架(含源码)

epoll详解