您的位置:首页 > 编程语言 > Java开发

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

2015-12-20 10:04 896 查看

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

您可能感兴趣的文章:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java ftp 服务器