欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java实现FTP服务器功能实例代码

程序员文章站 2024-03-07 19:48:39
ftp(file transfer protocol 文件传输协议)是internet 上用来传送文件的协议。在internet上通过ftp 服务器可以进行文件的上传(up...

ftp(file transfer protocol 文件传输协议)是internet 上用来传送文件的协议。在internet上通过ftp 服务器可以进行文件的上传(upload)或下载(download)。ftp是实时联机服务,在使用它之前必须是具有该服务的一个用户(用户名和口令),工作时客户端必须先登录到作为服务器一方的计算机上,用户登录后可以进行文件搜索和文件传送等有关操作,如改变当前工作目录、列文件目录、设置传输参数及传送文件等。使用ftp可以传送所有类型的文件,如文本文件、二进制可执行文件、图象文件、声音文件和数据压缩文件等。

ftp 命令

  ftp 的主要操作都是基于各种命令基础之上的。常用的命令有:
   设置传输模式,它包括ascⅱ(文本) 和binary 二进制模式;
   目录操作,改变或显示远程计算机的当前目录(cd、dir/ls 命令);
   连接操作,open命令用于建立同远程计算机的连接;close命令用于关闭连接;
   发送操作,put命令用于传送文件到远程计算机;mput 命令用于传送多个文件到远程计算机;
   获取操作,get命令用于接收一个文件;mget命令用于接收多个文件。

import java.net.socket; 
import org.apache.log4j.logger; 
/** 
 * 角色——服务器a 
 * @author leon 
 * 
 */ 
public class servera{ 
  public static void main(string[] args){ 
    final string f_dir = "c:/test";//根路径 
    final int port = 22;//监听端口号 
    logger.getrootlogger(); 
    logger logger = logger.getlogger("com"); 
    try{ 
      serversocket s = new serversocket(port); 
      logger.info("connecting to server a..."); 
      logger.info("connected successful! local port:"+s.getlocalport()+". default directory:'"+f_dir+"'."); 
      while( true ){ 
        //接受客户端请求 
        socket client = s.accept(); 
        //创建服务线程 
        new clientthread(client, f_dir).start(); 
      } 
    } catch(exception e) { 
      logger.error(e.getmessage()); 
      for(stacktraceelement ste : e.getstacktrace()){ 
        logger.error(ste.tostring()); 
      } 
    } 
  } 
} 
import java.io.bufferedreader;  
import java.io.file; 
import java.io.filenotfoundexception; 
import java.io.ioexception; 
import java.io.inputstream; 
import java.io.inputstreamreader; 
import java.io.outputstream; 
import java.io.printwriter; 
import java.io.randomaccessfile; 
import java.net.connectexception; 
import java.net.inetaddress; 
import java.net.serversocket; 
import java.net.socket; 
import java.net.unknownhostexception; 
import java.nio.charset.charset; 
import java.util.random; 
import org.apache.log4j.logger; 
/** 
 * 客户端子线程类 
 * @author leon 
 * 
 */ 
public class clientthread extends thread { 
  private socket socketclient;//客户端socket 
  private logger logger;//日志对象 
  private string dir;//绝对路径 
  private string pdir = "/";//相对路径 
  private final static random generator = new random();//随机数 
  public clientthread(socket client, string f_dir){ 
    this.socketclient = client; 
    this.dir = f_dir; 
  } 
  @override 
  public void run() { 
    logger.getrootlogger(); 
    logger = logger.getlogger("com"); 
    inputstream is = null; 
    outputstream os = null; 
    try { 
      is = socketclient.getinputstream(); 
      os = socketclient.getoutputstream(); 
    } catch (ioexception e) { 
      logger.error(e.getmessage()); 
      for(stacktraceelement ste : e.getstacktrace()){ 
        logger.error(ste.tostring()); 
      } 
    } 
    bufferedreader br = new bufferedreader(new inputstreamreader(is, 
        charset.forname("utf-8"))); 
    printwriter pw = new printwriter(os); 
    string clientip = socketclient.getinetaddress().tostring().substring(1);//记录客户端ip 
    string username = "not logged in";//用户名 
    string password = "";//口令 
    string command = "";//命令 
    boolean loginstuts = false;//登录状态 
    final string login_warning = "530 please log in with user and pass first."; 
    string str = "";//命令内容字符串 
    int port_high = 0; 
    int port_low = 0; 
    string retr_ip = "";//接收文件的ip地址 
    socket tempsocket = null; 
    //打印欢迎信息 
    pw.println("220-ftp server a version 1.0 written by leon guo"); 
    pw.flush(); 
    logger.info("("+username+") ("+clientip+")> connected, sending welcome message..."); 
    logger.info("("+username+") ("+clientip+")> 220-ftp server a version 1.0 written by leon guo"); 
    boolean b = true; 
    while ( b ){ 
      try { 
        //获取用户输入的命令 
        command = br.readline(); 
        if(null == command) break; 
      } catch (ioexception e) { 
        pw.println("331 failed to get command"); 
        pw.flush(); 
        logger.info("("+username+") ("+clientip+")> 331 failed to get command"); 
        logger.error(e.getmessage()); 
        for(stacktraceelement ste : e.getstacktrace()){ 
          logger.error(ste.tostring()); 
        } 
        b = false; 
      } 
      /* 
       * 访问控制命令 
       */ 
      // user命令 
      if(command.touppercase().startswith("user")){ 
        logger.info("(not logged in) ("+clientip+")> "+command); 
        username = command.substring(4).trim();  
        if("".equals(username)){ 
          pw.println("501 syntax error"); 
          pw.flush(); 
          logger.info("(not logged in) ("+clientip+")> 501 syntax error"); 
          username = "not logged in"; 
        } 
        else{ 
          pw.println("331 password required for " + username); 
          pw.flush(); 
          logger.info("(not logged in) ("+clientip+")> 331 password required for " + username); 
        } 
        loginstuts = false; 
      } //end user 
      // pass命令 
      else if(command.touppercase().startswith("pass")){ 
        logger.info("(not logged in) ("+clientip+")> "+command); 
        password = command.substring(4).trim();  
        if(username.equals("root") && password.equals("root")){ 
          pw.println("230 logged on"); 
          pw.flush(); 
          logger.info("("+username+") ("+clientip+")> 230 logged on"); 
//         logger.info("客户端 "+clientip+" 通过 "+username+"用户登录"); 
          loginstuts = true; 
        } 
        else{ 
          pw.println("530 login or password incorrect!"); 
          pw.flush(); 
          logger.info("(not logged in) ("+clientip+")> 530 login or password incorrect!"); 
          username = "not logged in"; 
        } 
      } //end pass 
      // pwd命令 
      else if(command.touppercase().startswith("pwd")){ 
        logger.info("("+username+") ("+clientip+")> "+command); 
        if(loginstuts){ 
//         logger.info("用户"+clientip+":"+username+"执行pwd命令"); 
          pw.println("257 /""+pdir+"/" is current directory"); 
          pw.flush(); 
          logger.info("("+username+") ("+clientip+")> 257 /""+pdir+"/" is current directory"); 
        } 
        else{ 
          pw.println(login_warning); 
          pw.flush(); 
          logger.info("("+username+") ("+clientip+")> "+login_warning); 
        } 
      } //end pwd 
      // cwd命令 
      else if(command.touppercase().startswith("cwd")){ 
        logger.info("("+username+") ("+clientip+")> "+command); 
        if(loginstuts){ 
          str = command.substring(3).trim(); 
          if("".equals(str)){ 
            pw.println("250 broken client detected, missing argument to cwd. /""+pdir+"/" is current directory."); 
            pw.flush(); 
            logger.info("("+username+") ("+clientip+")> 250 broken client detected, missing argument to cwd. /""+pdir+"/" is current directory."); 
          } 
          else{ 
            //判断目录是否存在 
            string tmpdir = dir + "/" + str; 
            file file = new file(tmpdir); 
            if(file.exists()){//目录存在 
              dir = dir + "/" + str; 
              if("/".equals(pdir)){ 
                pdir = pdir + str; 
              } 
              else{ 
                pdir = pdir + "/" + str; 
              } 
//             logger.info("用户"+clientip+":"+username+"执行cwd命令"); 
              pw.println("250 cwd successful. /""+pdir+"/" is current directory"); 
              pw.flush(); 
              logger.info("("+username+") ("+clientip+")> 250 cwd successful. /""+pdir+"/" is current directory"); 
            } 
            else{//目录不存在 
              pw.println("550 cwd failed. /""+pdir+"/": directory not found."); 
              pw.flush(); 
              logger.info("("+username+") ("+clientip+")> 550 cwd failed. /""+pdir+"/": directory not found."); 
            } 
          } 
        } 
        else{ 
          pw.println(login_warning); 
          pw.flush(); 
          logger.info("("+username+") ("+clientip+")> "+login_warning); 
        } 
      } //end cwd 
      // quit命令 
      else if(command.touppercase().startswith("quit")){ 
        logger.info("("+username+") ("+clientip+")> "+command); 
        b = false; 
        pw.println("221 goodbye"); 
        pw.flush(); 
        logger.info("("+username+") ("+clientip+")> 221 goodbye"); 
        try { 
          thread.currentthread(); 
          thread.sleep(1000); 
        } catch (interruptedexception e) { 
          logger.error(e.getmessage()); 
          for(stacktraceelement ste : e.getstacktrace()){ 
            logger.error(ste.tostring()); 
          } 
        } 
      } //end quit 
      /* 
       * 传输参数命令 
       */ 
      //port命令,主动模式传输数据 
      else if(command.touppercase().startswith("port")){ 
        logger.info("("+username+") ("+clientip+")> "+command); 
        if(loginstuts){ 
          try { 
            str = command.substring(4).trim(); 
            port_low = integer.parseint(str.substring(str.lastindexof(",")+1)); 
            port_high = integer.parseint(str.substring(0, str.lastindexof(",")) 
                .substring(str.substring(0, str.lastindexof(",")).lastindexof(",")+1)); 
            string str1 = str.substring(0, str.substring(0, str.lastindexof(",")).lastindexof(",")); 
            retr_ip = str1.replace(",", "."); 
            try { 
              //实例化主动模式下的socket 
              tempsocket = new socket(retr_ip,port_high * 256 + port_low); 
//             logger.info("用户"+clientip+":"+username+"执行port命令"); 
              pw.println("200 port command successful"); 
              pw.flush(); 
              logger.info("("+username+") ("+clientip+")> 200 port command successful"); 
            } catch (connectexception ce) { 
              pw.println("425 can't open data connection."); 
              pw.flush(); 
              logger.info("("+username+") ("+clientip+")> 425 can't open data connection."); 
              logger.error(ce.getmessage()); 
              for(stacktraceelement ste : ce.getstacktrace()){ 
                logger.error(ste.tostring()); 
              } 
            } catch (unknownhostexception e) { 
              logger.error(e.getmessage()); 
              for(stacktraceelement ste : e.getstacktrace()){ 
                logger.error(ste.tostring()); 
              } 
            } catch (ioexception e) { 
              logger.error(e.getmessage()); 
              for(stacktraceelement ste : e.getstacktrace()){ 
                logger.error(ste.tostring()); 
              } 
            } 
          } catch (numberformatexception e) { 
            pw.println("503 bad sequence of commands."); 
            pw.flush(); 
            logger.info("("+username+") ("+clientip+")> 503 bad sequence of commands."); 
            logger.error(e.getmessage()); 
            for(stacktraceelement ste : e.getstacktrace()){ 
              logger.error(ste.tostring()); 
            } 
          } 
        } 
        else{ 
          pw.println(login_warning); 
          pw.flush(); 
          logger.info("("+username+") ("+clientip+")> "+login_warning); 
        } 
      } //end port 
      //pasv命令,被动模式传输数据 
      else if(command.touppercase().startswith("pasv")) {  
        logger.info("("+username+") ("+clientip+")> "+command); 
        if(loginstuts){ 
          serversocket ss = null; 
          while( true ){ 
            //获取服务器空闲端口 
            port_high = 1 + generator.nextint(20); 
            port_low = 100 + generator.nextint(1000); 
            try { 
              //服务器绑定端口 
              ss = new serversocket(port_high * 256 + port_low); 
              break; 
            } catch (ioexception e) { 
              continue; 
            } 
          } 
//         logger.info("用户"+clientip+":"+username+"执行pasv命令"); 
          inetaddress i = null; 
          try { 
            i = inetaddress.getlocalhost(); 
          } catch (unknownhostexception e1) { 
            e1.printstacktrace(); 
          } 
          pw.println("227 entering passive mode ("+i.gethostaddress().replace(".", ",")+","+port_high+","+port_low+")"); 
          pw.flush(); 
          logger.info("("+username+") ("+clientip+")> 227 entering passive mode ("+i.gethostaddress().replace(".", ",")+","+port_high+","+port_low+")"); 
          try { 
            //被动模式下的socket 
            tempsocket = ss.accept(); 
            ss.close(); 
          } catch (ioexception e) { 
            logger.error(e.getmessage()); 
            for(stacktraceelement ste : e.getstacktrace()){ 
              logger.error(ste.tostring()); 
            } 
          } 
        } 
        else{ 
          pw.println(login_warning); 
          pw.flush(); 
          logger.info("("+username+") ("+clientip+")> "+login_warning); 
        } 
      } //end pasv 
      //retr命令 
      else if(command.touppercase().startswith("retr")){ 
        logger.info("("+username+") ("+clientip+")> "+command); 
        if(loginstuts){ 
          str = command.substring(4).trim(); 
          if("".equals(str)){ 
            pw.println("501 syntax error"); 
            pw.flush(); 
            logger.info("("+username+") ("+clientip+")> 501 syntax error"); 
          } 
          else { 
            try { 
              pw.println("150 opening data channel for file transfer."); 
              pw.flush(); 
              logger.info("("+username+") ("+clientip+")> 150 opening data channel for file transfer."); 
              randomaccessfile outfile = null; 
              outputstream outsocket = null; 
              try { 
                //创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称 
                outfile = new randomaccessfile(dir+"/"+str,"r"); 
                outsocket = tempsocket.getoutputstream();  
              } catch (filenotfoundexception e) {  
                logger.error(e.getmessage()); 
                for(stacktraceelement ste : e.getstacktrace()){ 
                  logger.error(ste.tostring()); 
                } 
              } catch (ioexception e) { 
                logger.error(e.getmessage()); 
                for(stacktraceelement ste : e.getstacktrace()){ 
                  logger.error(ste.tostring()); 
                } 
              }  
              byte bytebuffer[]= new byte[1024];  
              int length;  
              try{  
                while((length = outfile.read(bytebuffer)) != -1){  
                  outsocket.write(bytebuffer, 0, length);  
                }  
                outsocket.close();  
                outfile.close();  
                tempsocket.close();  
              }  
              catch(ioexception e){ 
                logger.error(e.getmessage()); 
                for(stacktraceelement ste : e.getstacktrace()){ 
                  logger.error(ste.tostring()); 
                } 
              } 
//             logger.info("用户"+clientip+":"+username+"执行retr命令"); 
              pw.println("226 transfer ok"); 
              pw.flush(); 
              logger.info("("+username+") ("+clientip+")> 226 transfer ok"); 
            } catch (exception e){ 
              pw.println("503 bad sequence of commands."); 
              pw.flush(); 
              logger.info("("+username+") ("+clientip+")> 503 bad sequence of commands."); 
              logger.error(e.getmessage()); 
              for(stacktraceelement ste : e.getstacktrace()){ 
                logger.error(ste.tostring()); 
              } 
            } 
          } 
        } 
        else{ 
          pw.println(login_warning); 
          pw.flush(); 
          logger.info("("+username+") ("+clientip+")> "+login_warning); 
        } 
      }//end retr 
      //stor命令 
      else if(command.touppercase().startswith("stor")){  
        logger.info("("+username+") ("+clientip+")> "+command); 
        if(loginstuts){ 
          str = command.substring(4).trim(); 
          if("".equals(str)){ 
            pw.println("501 syntax error"); 
            pw.flush(); 
            logger.info("("+username+") ("+clientip+")> 501 syntax error"); 
          } 
          else { 
            try { 
              pw.println("150 opening data channel for file transfer.");  
              pw.flush(); 
              logger.info("("+username+") ("+clientip+")> 150 opening data channel for file transfer."); 
              randomaccessfile infile = null; 
              inputstream insocket = null; 
              try { 
                infile = new randomaccessfile(dir+"/"+str,"rw"); 
                insocket = tempsocket.getinputstream();  
              } catch (filenotfoundexception e) {  
                logger.error(e.getmessage());  
                for(stacktraceelement ste : e.getstacktrace()){ 
                  logger.error(ste.tostring()); 
                } 
              } catch (ioexception e) { 
                logger.error(e.getmessage());  
                for(stacktraceelement ste : e.getstacktrace()){ 
                  logger.error(ste.tostring()); 
                } 
              }  
              byte bytebuffer[] = new byte[1024];  
              int length;  
              try{ 
                while((length =insocket.read(bytebuffer) )!= -1){  
                  infile.write(bytebuffer, 0, length);  
                } 
                insocket.close();  
                infile.close();  
                tempsocket.close();  
              }  
              catch(ioexception e){ 
                logger.error(e.getmessage()); 
                for(stacktraceelement ste : e.getstacktrace()){ 
                  logger.error(ste.tostring()); 
                } 
              } 
//             logger.info("用户"+clientip+":"+username+"执行stor命令"); 
              pw.println("226 transfer ok"); 
              pw.flush(); 
              logger.info("("+username+") ("+clientip+")> 226 transfer ok"); 
            } catch (exception e){ 
              pw.println("503 bad sequence of commands."); 
              pw.flush(); 
              logger.info("("+username+") ("+clientip+")> 503 bad sequence of commands."); 
              logger.error(e.getmessage()); 
              for(stacktraceelement ste : e.getstacktrace()){ 
                logger.error(ste.tostring()); 
              } 
            } 
          } 
        } else { 
          pw.println(login_warning); 
          pw.flush(); 
          logger.info("("+username+") ("+clientip+")> "+login_warning); 
        } 
      } //end stor 
      //nlst命令 
      else if(command.touppercase().startswith("nlst")) {  
        logger.info("("+username+") ("+clientip+")> "+command); 
        if(loginstuts){ 
          try { 
            pw.println("150 opening data channel for directory list.");  
            pw.flush(); 
            logger.info("("+username+") ("+clientip+")> 150 opening data channel for directory list."); 
            printwriter pwr = null; 
            try { 
              pwr= new printwriter(tempsocket.getoutputstream(),true); 
            } catch (ioexception e1) { 
              e1.printstacktrace(); 
            }  
            file file = new file(dir);  
            string[] dirstructure = new string[10];  
            dirstructure= file.list();  
            for(int i=0;i<dirstructure.length;i++){ 
              pwr.println(dirstructure[i]);  
            } 
            try { 
              tempsocket.close(); 
              pwr.close(); 
            } catch (ioexception e) { 
              logger.error(e.getmessage()); 
              for(stacktraceelement ste : e.getstacktrace()){ 
                logger.error(ste.tostring()); 
              } 
            }  
//           logger.info("用户"+clientip+":"+username+"执行nlst命令"); 
            pw.println("226 transfer ok");  
            pw.flush(); 
            logger.info("("+username+") ("+clientip+")> 226 transfer ok"); 
          } catch (exception e){ 
            pw.println("503 bad sequence of commands."); 
            pw.flush(); 
            logger.info("("+username+") ("+clientip+")> 503 bad sequence of commands."); 
            logger.error(e.getmessage()); 
            for(stacktraceelement ste : e.getstacktrace()){ 
              logger.error(ste.tostring()); 
            } 
          } 
        }else{ 
          pw.println(login_warning); 
          pw.flush(); 
          logger.info("("+username+") ("+clientip+")> "+login_warning); 
        } 
      } //end nlst 
      //list命令 
      else if(command.touppercase().startswith("list")) {  
        logger.info("("+username+") ("+clientip+")> "+command); 
        if(loginstuts){ 
          try{ 
            pw.println("150 opening data channel for directory list.");  
            pw.flush(); 
            logger.info("("+username+") ("+clientip+")> 150 opening data channel for directory list."); 
            printwriter pwr = null; 
            try { 
              pwr= new printwriter(tempsocket.getoutputstream(),true); 
            } catch (ioexception e) { 
              logger.error(e.getmessage()); 
              for(stacktraceelement ste : e.getstacktrace()){ 
                logger.error(ste.tostring()); 
              } 
            }  
            ftputil.getdetaillist(pwr, dir); 
            try { 
              tempsocket.close(); 
              pwr.close(); 
            } catch (ioexception e) { 
              logger.error(e.getmessage()); 
              for(stacktraceelement ste : e.getstacktrace()){ 
                logger.error(ste.tostring()); 
              } 
            }  
//           logger.info("用户"+clientip+":"+username+"执行list命令"); 
            pw.println("226 transfer ok");  
            pw.flush(); 
            logger.info("("+username+") ("+clientip+")> 226 transfer ok"); 
          } catch (exception e){ 
            pw.println("503 bad sequence of commands."); 
            pw.flush(); 
            logger.info("("+username+") ("+clientip+")> 503 bad sequence of commands."); 
            logger.error(e.getmessage()); 
            for(stacktraceelement ste : e.getstacktrace()){ 
              logger.error(ste.tostring()); 
            } 
          } 
        } else { 
          pw.println(login_warning); 
          pw.flush(); 
          logger.info("("+username+") ("+clientip+")> "+login_warning); 
        } 
      } //end list 
      // 输入非法命令 
      else{ 
        logger.info("("+username+") ("+clientip+")> "+command); 
        pw.println("500 syntax error, command unrecognized."); 
        pw.flush(); 
        logger.info("("+username+") ("+clientip+")> 500 syntax error, command unrecognized."); 
      } 
    } //end while 
    try { 
      logger.info("("+username+") ("+clientip+")> disconnected."); 
//     logger.info("用户"+clientip+":"+username+"退出"); 
      br.close(); 
      socketclient.close(); 
      pw.close(); 
      if(null != tempsocket){ 
        tempsocket.close(); 
      } 
    } catch (ioexception e) { 
      logger.error(e.getmessage()); 
      for(stacktraceelement ste : e.getstacktrace()){ 
        logger.error(ste.tostring()); 
      } 
    } 
  } 
} 
import java.io.file;  
import java.io.printwriter; 
import java.text.simpledateformat; 
import java.util.date; 
/** 
 * ftp工具类 
 * @author leon 
 * 
 */ 
public class ftputil { 
  public static void getdetaillist(printwriter pw, string path){ 
    file dir = new file(path); 
    if (!dir.isdirectory()) { 
      pw.println("500 no such file or directory./r/n"); 
    } 
    file[] files = dir.listfiles(); 
    string modifydate; 
    for (int i = 0; i < files.length; i++) { 
      modifydate = new simpledateformat("yyyy/mm/dd hh:mm:ss") 
          .format(new date(files[i].lastmodified())); 
      if (files[i].isdirectory()) { 
        pw.println("drwxr-xr-x ftp   ftp      0 " 
            + modifydate + " " + files[i].getname()); 
      } else { 
        pw.println("-rw-r-r--1 ftp   ftp      " 
            + files[i].length() + " " + modifydate + " " 
            + files[i].getname()); 
      } 
      pw.flush(); 
    } 
    pw.println("total:" + files.length); 
  } 
} 
### set log levels ### 
log4j.logger.com =debug,stdout,d,e 
### 输出到控制台 ### 
log4j.appender.stdout=org.apache.log4j.consoleappender 
log4j.appender.stdout.target=system.out 
log4j.appender.stdout.layout=org.apache.log4j.patternlayout 
log4j.appender.stdout.layout.conversionpattern = %d{absolute} %5p %c{1}:%l - %m%n 
## 输出debug级别以上的日志 
log4j.appender.d=org.apache.log4j.dailyrollingfileappender 
log4j.appender.d.file=c:/logs/logs.log 
log4j.appender.d.append =true 
## 输出debug级别以上的日志 
log4j.appender.d.threshold=debug 
log4j.appender.d.layout=org.apache.log4j.patternlayout 
log4j.appender.d.layout.conversionpattern = %-d{yyyy-mm-dd hh:mm:ss} [ %t:%r ] - [ %p ] %m%n 
### 保存异常信息到单独文件 ### 
log4j.appender.e=org.apache.log4j.dailyrollingfileappender 
## 异常日志文件名 
log4j.appender.e.file=c:/logs/errors.log 
log4j.appender.e.append=true 
## 只输出error级别以上的日志!!! 
log4j.appender.e.threshold=error 
log4j.appender.e.layout=org.apache.log4j.patternlayout 
log4j.appender.e.layout.conversionpattern = %-d{yyyy-mm-dd hh:mm:ss} [ %t:%r ] - [ %p ] %m%n 

以上内容是小编给大家介绍的java实现ftp服务器功能实例代码的相关知识,希望大家喜欢。