网络编程实现FTP服务器

1:FTP

文件传输协议(File Transfer Protocol,FTP)是Internet上使用最广泛的文件传送协议,它是TCP/IP协议族中的协议之一,其目标是提高文件的共享性,提供可靠高效的数据传输服务。

FTP由RFC959定义,是基于TCP服务的应用层协议。FTP服务器一般运行在TCP的20,21号两个端口,端口20用于在客户端和服务器之间的数据传输;端口21用于传输控制流,并且是控制命令通向FTP服务器的入口。

2:FTP的工作原理:

  (1)FTP的运作流程:

      FTP是应用层的协议,它基于传输层TCP协议传输,TCP建立连接需要三次握手,FTP服务一般运行在20和21两个端口,端口20用于在客户端和服务器之间传输数据流,而端口21用于传输控制流.这两种传输都需要经过三次握手。

   (2)文件传输中的处理过程:

     建立了FTP的运作流程和文件传输处理过程的模型,我们就来了解主动连接。

     1)三次握手的第一次:客服端发送FTP命令到服务端

        客服端是用Windows命令进行操作的,下面是我们需要用到的命令

        打开服务器(自己编程实现的),然后在Windows界面去连接。

      

 

     以下是Windows中FTP命令,但最终会被用户协议解释器转换成相应的FTP命令发送给服务端;

Debug 可以看到所发送的内容。

1        ftp> help 列出 ftp 文件传输,可使用的任何命令。
2        ftp> !ls 列出本地工作站,目前目录下的所有文件名。
3     ftp> !pwd 列出本地工作站,目前所在的工作目录位置。
4     ftp> ls 列出远端工作站目前目录下的所有文件名。
5     ftp> dir 列出远端工作站目前目录下的所有文件名(略同于 UNIX 的 ls -l 指令).
6     ftp> pwd 列出远端工作站目前所在的目录位置。
7     ftp> cd dir1 更改远端工作站的工作目录位置至 dir1 下。
8     ftp> get file1 将远端工作站的文件 file1 ,拷贝到本地工作站中。
9     ftp> put file2 将本地工作站的文件 file2 ,拷贝到远端工作站中。

     第一次握手客户端发送给服务器的内容是

发送的格式是 PORT x,x,x,x,pH,pL   下面是一个例子

PORT 127,0,0,1,208,6     中 127.0.0.1 是客户端发送给服务端的IP地址(将逗号转换成小数点)。因为端口是采用16位端口地址,所以告诉服务器,客户端正在监听的端口号是  208 * 256 + 6(PH * 256 + PL), 建立数据通道的时候会用。

  2)三次握手第二次:FTP应答

    应答都是ASCII码形式的3位数字,并很有报文选项。其原因是软件系统需要根据数据代码来决定如何应答。

    应答3位码中的每一位都有不同的含义,这里是一些典型的应答,都带有一个可能得报文串

    125 数据连接已经打开;传输开始;

    150 数据通道已打开,开始传输文件;

    200 新的连接已打开,请发送命令吧;

    220 命令通道已建立,等待命令;

    230 登录成功;

    214 帮助报文(面向用户);

    331 用户名就绪,要求输入口令;

    425 建立数据通道失败;

    501 语法错误;

    530 用户或密码错误;

 3)三次握手第三次:发出相应的FTP命令;

     文件操作命令

     LIST

     ERTR

     ... ...

通过三次握手,实现FTP文件传输,下面是实现FTP服务器部分功能的代码:

  1 import java.net.*;
  2 import java.io.*;
  3 import java.nio.charset.Charset;
  4 import java.util.Random;
  5 
  6 public class ServerBO{
  7 
  8    public static void main(String[] args){
  9       final String F_DIR = "D:/网络技术/FTP服务器/服务器中的文件";
 10       ServerSocket server_socket = null;
 11       try{
 12          server_socket = new ServerSocket(21);
 13          while(true){
 14             Socket socket = server_socket.accept();
 15             System.out.println("用户连接成功!");
 16             new ClientThread(socket,F_DIR).start();
 17          }
 18       }catch(Exception e){
 19          e.printStackTrace();
 20       }
 21    }
 22 }
 23 
 24 class ClientThread extends Thread{
 25     Socket socket;
 26     String dir = "";
 27     public ClientThread(Socket s,String F_DIR){
 28        this.socket = s;
 29        this.dir = F_DIR;
 30     }
 31     
 32     public void run(){
 33         InputStream is = null;
 34         OutputStream os= null;
 35         try{
 36            is = socket.getInputStream();
 37            os = socket.getOutputStream();
 38         }catch(Exception e){
 39            e.printStackTrace();
 40         }
 41         
 42         BufferedReader br = new BufferedReader(new InputStreamReader(is,Charset.forName("UTF-8")));
 43         PrintWriter pw = new PrintWriter(os,true);
 44         String clientIP = socket.getInetAddress().toString().substring(1);
 45         
 46         String username ="not login in";
 47         String password = "";
 48         String command = "";
 49         boolean loginStatus = false;
 50         final String LOGIN_WARNING = "530 Please log in with USER and PASS first."; 
 51         String str = ""; //命令内容字符串
 52         int port_high = 0;
 53         int port_low = 0;
 54         String retr_ip = "";//接受文件的IP地址
 55         
 56         Socket tempsocket = null;
 57         //打印欢迎信息
 58         pw.println("220 FTP Server A version 1.0 written by root");
 59         pw.flush();    
 60         boolean b = true;
 61         while(b){
 62            try{
 63               command = br.readLine();
 64               System.out.println(command);
 65               if(null == command) break;
 66     
 67            }catch(Exception e){
 68              pw.println("331 Failed to get commend");
 69              pw.flush();
 70              e.printStackTrace();
 71              b = false;
 72            }
 73            
 74           if(command.toUpperCase().startsWith("OPTS")){   
 75                 //告诉用户已经准备好了
 76                 System.out.println(command);
 77                 pw.println("FTP is ready");
 78                 pw.flush();
 79            }
 80            else if(command.toUpperCase().startsWith("USER")){
 81               username = command.substring(4).trim();
 82               if("".equals(username)){
 83                  pw.println("501 Syntax error");
 84                  pw.flush();
 85                  username = "not logged in";
 86               }else{
 87                 pw.println("331 Password required for " + username);
 88                 pw.flush();
 89               }
 90               loginStatus = false;
 91            }
 92            
 93             else if(command.toUpperCase().startsWith("PASS")){
 94               password = command.substring(4).trim();
 95               if(username.equals("root") && password.equals("root")){
 96                  pw.println("230 logged in");
 97                  pw.flush();
 98                  loginStatus = true;
 99               }else{
100                  pw.println("530 login or password incorrect!");
101                  pw.flush();
102                  username = "not logged in";
103               }
104            }
105            else if(command.toUpperCase().startsWith("PORT")){
106               if(loginStatus){
107                  try{
108                    str = command.substring(4).trim();
109                    port_low = Integer.parseInt(str.substring(str.lastIndexOf(",")+1));
110                    port_high= Integer.parseInt(str.substring(0,str.lastIndexOf(","))
111                               .substring(str.substring(0,str.lastIndexOf(",")).lastIndexOf(",")+1));
112                    String str1 = str.substring(0,str.substring(0,str.lastIndexOf(",")).lastIndexOf(","));
113                    retr_ip = str1.replace(",",".");
114                    int port = socket.getPort();       
115                    try{
116                      tempsocket = new Socket(retr_ip,port_high * 256 + port_low);  //这句话出现了问题
117                      pw.println("200 新的连接已经打开!");
118                      pw.flush();
119                    }catch(Exception e){
120                      pw.println("425 不能建立数据连接!");
121                      pw.flush();
122                      e.printStackTrace();
123                    }
124                  }catch (NumberFormatException e) {  
125                         pw.println("503 Bad sequence of commands.");  
126                         pw.flush(); 
127                 }        
128               }else{
129                 pw.println(LOGIN_WARNING);
130                 pw.flush();
131               }
132            }else if (command.toUpperCase().startsWith("LIST")){
133               if(loginStatus){
134                  try{
135                     pw.println("150 opening data channel for directory list");
136                     pw.flush();
137                     PrintWriter pwr = null;
138                     try{
139                        pwr = new PrintWriter(tempsocket.getOutputStream(),true);
140                     }catch(Exception e){
141                        e.printStackTrace();
142                     }
143                     
144                     FtpUtil.getDetailList(pwr,dir);
145                     try{
146                        tempsocket.close();
147                        pwr.close();
148                     }catch(Exception e){
149                        e.printStackTrace();
150                     }
151                     
152                     pw.println("226 transfer OK");
153                     pw.flush();
154                  }catch(Exception e){
155                  
156                     e.printStackTrace();
157                  }
158                  
159               }else{
160                  pw.println(LOGIN_WARNING);
161                  pw.flush();
162               }
163            }else if(command.toUpperCase().startsWith("RETR")){   
164                 if(loginStatus){  
165                     str = command.substring(4).trim();  
166                     if("".equals(str)){  
167                         pw.println("501 Syntax error");  
168                         pw.flush();   
169                     }  
170                     else {  
171                         try {  
172                             pw.println("150 Opening data channel for file transfer.");  
173                             pw.flush();  
174                             RandomAccessFile outfile = null;  
175                             OutputStream outsocket = null;  
176                             try {  
177                                 outfile = new RandomAccessFile(new File(dir+"/"+str),"rw");  
178                                 outsocket = tempsocket.getOutputStream();   
179                             } catch (Exception e) { 
180                                 e.printStackTrace();                            
181                             }   
182                             byte bytebuffer[]= new byte[1024];   
183                             int length;   
184                             try{   
185                                 while((length = outfile.read(bytebuffer)) != -1){                                  
186                                     outsocket.write(bytebuffer, 0, length);   
187                                 }   
188                                 outsocket.close();   
189                                 outfile.close();   
190                                 tempsocket.close();   
191                             }   
192                             catch(IOException e){  
193                                 e.printStackTrace();
194                             }   
195                             pw.println("226 Transfer OK");  
196                             pw.flush();   
197                         } catch (Exception e){  
198                             e.printStackTrace();
199                             pw.println("503 Bad sequence of commands.");  
200                             pw.flush();  
201                         }  
202                     }  
203                 }  
204                 else{  
205                     pw.println(LOGIN_WARNING);  
206                     pw.flush();  
207                 }  
208             }else {
209                 pw.println("500 Systax error, command unrecognized.");
210                 pw.flush();
211             }   
212         }
213         
214         try{
215            br.close();
216            socket.close();
217            pw.close();
218            if(null != tempsocket){
219               tempsocket.close();
220            }
221         }catch(Exception e){
222            e.printStackTrace();
223         }
224     }
225 }
 1 import java.io.File;    
 2 import java.io.PrintWriter;  
 3 import java.text.SimpleDateFormat;  
 4 import java.util.Date;  
 5   
 6 /** 
 7  * FTP工具类 
 8  * @author Leon 
 9  * 
10  */  
11 public class FtpUtil {  
12       
13     public static void getDetailList(PrintWriter pwr, String path) throws Exception{  
14         File dir = new File(path);  
15         if (!dir.isDirectory()) {  
16             pwr.println("500 No such file or directory./r/n");
17             pwr.flush();            
18         }  
19         File[] files = dir.listFiles();  
20         String modifyDate;  
21         for (int i = 0; i < files.length; i++) {  
22             modifyDate = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date(files[i].lastModified()));  
23             if (files[i].isDirectory()) {  
24                 pwr.println(modifyDate + " " + files[i].getName()); 
25                 pwr.flush();                
26                 System.out.println(modifyDate + " " + files[i].getName());                        
27             } else {  
28                 pwr.println(modifyDate+"  "+ files[i].getName());
29                 pwr.flush();
30                 System.out.println(modifyDate + " " + files[i].getName());                
31             }  
32               
33         }  
34         System.out.println("total:" + files.length);
35         pwr.println("total:" + files.length);
36         pwr.flush();        
37     }  
38   
39 } 

 

posted @ 2016-07-03 16:17  飞出四季做的茧  阅读(1087)  评论(0编辑  收藏  举报