栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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; 
 
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; 
 
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 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; 
 
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服务器功能实例代码的相关知识,希望大家喜欢。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/150792.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号