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服务器功能实例代码的相关知识,希望大家喜欢。
本文地址:https://www.stayed.cn/item/7072
转载请注明出处。
本站部分内容来源于网络,如侵犯到您的权益,请 联系我