來源:CHEN俊銘 發(fā)布時間:2018-11-21 15:27:32 閱讀量:1375
開啟FTP服務器(編程)
開啟FTP服務器編程
編程要點
項目結構
主要源碼
附言
編程要點
其實FTP的服務器編程很簡單,只要兩點,第一點就是資料的儲備,這一點在我的另一篇博文FTP資料已經(jīng)有了,第二點,也就是我摸索了很久的一點,那就是FTP的套路。
在使用window的cmd與我搭的ftp交互的過程中,我深深地感受到被套路,而且我還得主動去配合他的套路,比如說,我給出指令(紅框)
你覺得我是自己可以隨意輸入嗎?NO,不可以的,只有當響應碼返回的時候,控制臺才會開啟某個輸入給你輸入。也就是說,如果服務器沒有返回響應碼,你是沒辦法輸入的,就像這樣
如果你編程的時候,不給他返回響應碼,那么就沒有輸入的可能,那個光標只是讓你看看,不能輸入的。所以,每次都寫執(zhí)行的時候,都要先告訴控制臺,給他相應的響應碼。每條指令都有相應的響應碼。
項目結構
E-R關系
主要源碼
Command.java
package com.chen.model;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
public class Command {
private Socket socket;
private BufferedReader reader;
private BufferedWriter writer;
private User user = new User();
private String remoteHost;// 遠程主機
private int remotePort;// 遠程端口號
private static Socket dSocket = null;
private static String[] strs = new String[10];// 用來存儲分解的指令//從中可以獲得我們要的字符串
public Command(Socket socket, BufferedReader reader, BufferedWriter writer) {
super();
this.socket = socket;
this.reader = reader;
this.writer = writer;
response("220 Welcome to use.");
}
/**
* 服務器響應
*
* @param str
*/
private void response(String str) {
try {
writer.write(str);
writer.newLine();
writer.flush();
System.out.println("服務響應:" + str);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 打印信息
*
* @param dWriter
* @param str
*/
private void printStr(BufferedWriter dWriter, String str) {
try {
dWriter.write(str);
dWriter.newLine();
dWriter.flush();
System.out.println("打印信息:" + str);
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean command(String str) {
try {
strs = str.split(" ");
} catch (Exception e) {
// 今天是端午節(jié),我卻回不了家,沒有粽子吃,我感到一股巨大的悲傷
// 而且更傷心的是 我還得打碼
// 流淚
// 快瞎了
// 智商歸零ing
strs[0] = str;// 如果沒有可以切割的話說明就是單字符串的指令
}
System.out.println("用戶命令:"+user.getUser()+" > "+ str);
str = strs[0];// 命令字
str = str.toUpperCase();
try {
switch (str) {
case "OPTS": {
response("332 User required.");// 用戶名
}
break;
case "XMKD": {// 創(chuàng)建新文件
commandXMKD();
}
case "USER": {
user.setUser(strs[1]);// 裝上名字
response("331 Password required.");
}
break;
case "PASS": {
commandPass();
}
break;
case "QUIT": {
response("221 thank for use.");
user.setWorkDir("");
}
break;
case "PORT": {// port IP 地址和兩字節(jié)的端口 ID
commandPORT();
}// DIR 命令 //接下來執(zhí)行List命令
break;
case "LIST": {// dir命令
commandList();
}
break;
case "CWD": {// CD 命令
commandCWD();
}
break;
case "RETR": {// GET 命令 :下載文件
commandRETR();
}
break;
case "STOR": {// SEND 命令:上傳文件
commandSTOR();
}
break;
default: {
response("500 command param error.");
}
break;
}
} catch (Exception e) {
response("500 command param error.");// 錯誤
}
return true;
}
private void commandXMKD() {
String mkdirFile = user.getWorkDir() + "/" + strs[1];
File file = new File(mkdirFile);
if (!file.exists()) {
file.mkdir();
}
}
/**
* 上傳文件
*/
private void commandSTOR() {
String oldFileUrl = "";
if (strs[1].contains(user.getOriDir())) {// 萬一客戶直接就把全路徑寫了呢
oldFileUrl = strs[1];
} else {
oldFileUrl = user.getWorkDir() + "/" + strs[1];// 請求文件的全路徑
}
BufferedOutputStream bos = null;
BufferedInputStream bis = null;
// 上傳文件
try {
dSocket = new Socket(remoteHost, remotePort);
bos = new BufferedOutputStream(new FileOutputStream(oldFileUrl));
bis = new BufferedInputStream(dSocket.getInputStream());// 客戶端塞過來的流
// 我就吃吃吃
byte[] buf = new byte[1024];
int l = 0;
while ((l = bis.read(buf, 0, 1024)) != -1) {
bos.write(buf, 0, l);
}
response("150 Opening connection for " + oldFileUrl);
response("226 Transfer complete.");
} catch (Exception e) {
e.printStackTrace();
response("550 The system cannot find the path specified.");
} finally {
try {
bis.close();
bos.close();
dSocket.close();
dSocket = null;
} catch (IOException e) {
e.printStackTrace();
}
}
response("226 Transfer complete.");
}
/**
* 下載文件
*/
private boolean commandRETR() {
BufferedInputStream fin = null;
PrintStream dout = null;
String oldFileUrl = user.getWorkDir() + "/" + strs[1];// 請求文件的全路徑
File file = new File(strs[1]);
if (!file.exists()) {// 萬一用戶用的是全路徑
file = new File(oldFileUrl);
if (!file.exists()) { // 萬一用的是缺省呢
response("550 The system cannot find the file specified.");// 沒有該文件
return false;
}
}
// 下載文件
try {
response("150 Opening connection for " + oldFileUrl);
dSocket = new Socket(remoteHost, remotePort);
fin = new BufferedInputStream(new FileInputStream(oldFileUrl));
dout = new PrintStream(dSocket.getOutputStream(), true);
byte[] buf = new byte[1024];
int l = 0;
while ((l = fin.read(buf, 0, 1024)) != -1) {
dout.write(buf, 0, l);// 往dataSocket死命地寫 沒有粽子吃的悲傷
// 反正客戶端會收到悲傷,收不到我的注釋
}
response("226 Transfer complete.");
} catch (Exception e) {
e.printStackTrace();
response("550 The system cannot find the path specified.");
return false;
} finally {
try {
fin.close();
dout.close();
dSocket.close();
dSocket = null;
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
/**
* 用來進入某個文件
*/
private boolean commandCWD() {
// 怎么說呢,其實很簡單吧,應該就是把用戶文件工作區(qū)拼上請求字符
if ("/".equals(strs[1]) || "\\".equals(strs[1])) {
user.setWorkDir(user.getOriDir());
response("250 Requested file action okay,the directory is "
+ user.getWorkDir());
return true;
}
// 判斷文件夾存不存在
File workDir = new File(user.getWorkDir());
File[] files = workDir.listFiles(new FileFilter() {
@Override
public boolean accept(File paramFile) {
if (paramFile.getName().contains("."))
return false;
return true;
}
});// 文件夾的文件夾
boolean flag = false;
for (File f : files) {
if (f.getName().equals(strs[1])) {
flag = true;
break;
}
}
if (flag) {
user.setWorkDir(user.getWorkDir() + "/" + strs[1]);
response("250 Requested file action okay,the directory is "
+ user.getWorkDir());
} else {
response("550 The directory does not exists");
}
response("250 CWD command successful.");
return true;
}
/**
* Pass 命令:驗證密碼 strs[1]:命令字符串的第二個 一般是參數(shù)
*/
private void commandPass() {
// 檢查 用戶是否存在
boolean isUser = false;
ArrayList<User> users = User.getUsers();
for (User u : users) {
if (user.getUser().equals(u.getUser())
&& strs[1].equals(u.getPassword())) {
isUser = true;
user = u;// 整個user都賦值過去
break;
}
}
if (isUser) {// 是我們的用戶
response("230 User logged in.");
} else {// 非法用戶
response("530 Not logged in,you account is wrong.");
}
}
/**
* post 請求命令:
*/
private void commandPORT() {
String[] temp = strs[1].split(",");
remoteHost = temp[0] + "." + temp[1] + "." + temp[2] + "." + temp[3];
String port1 = null;
String port2 = null;
if (temp.length == 6) {
port1 = temp[4];
port2 = temp[5];
} else {
port1 = "0";
port2 = temp[4];
}
remotePort = Integer.parseInt(port1) * 256 + Integer.parseInt(port2);
response("200 PORT command successful.");
}
/**
* List 命令:顯示所有的文件
*/
private void commandList() {
response("150 Data connection already open; Transfer starting.");
OutputStreamWriter dStream = null;
BufferedWriter dWriter = null;
try {
dSocket = new Socket(remoteHost, remotePort);
dStream = new OutputStreamWriter(dSocket.getOutputStream(),"gb2312");
dWriter = new BufferedWriter(dStream);
// 要輸出的數(shù)據(jù)
File file = new File(user.getWorkDir());
File[] files = file.listFiles();
String fMess;// 文件信息
String tab = " ";// 5個空格
for (File f : files) {
fMess = TimeDealer.timeFormat(f.lastModified())// 時間
+ tab // 格式
+ (f.isFile() ? tab : "<DIR>") + tab // 格式
+ f.getName();
printStr(dWriter, fMess);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
dWriter.close();
dStream.close();
dSocket.close();
dSocket = null;
} catch (IOException e) {
e.printStackTrace();
}
}
response("226 transfer complete");
}
}
---------------------