来源:CHEN俊铭 发布时间:2018-11-21 15:27:32 阅读量:1373
开启FTP服务器(编程)
开启FTP服务器编程
编程要点
项目结构
主要源码
附言
编程要点
其实FTP的服务器编程很简单,只要两点,第一点就是资料的储备,这一点在我的另一篇博文FTP资料已经有了,第二点,也就是我摸索了很久的一点,那就是FTP的套路。
在使用window的cmd与我搭的ftp交互的过程中,我深深地感受到被套路,而且我还得主动去配合他的套路,比如说,我给出指令(红框)
你觉得我是自己可以随意输入吗?NO,不可以的,只有当响应码返回的时候,控制台才会开启某个输入给你输入。也就是说,如果服务器没有返回响应码,你是没办法输入的,就像这样
如果你编程的时候,不给他返回响应码,那么就没有输入的可能,那个光标只是让你看看,不能输入的。所以,每次都写执行的时候,都要先告诉控制台,给他相应的响应码。每条指令都有相应的响应码。
项目结构
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) {
// 今天是端午节,我却回不了家,没有粽子吃,我感到一股巨大的悲伤
// 而且更伤心的是 我还得打码
// 流泪
// 快瞎了
// 智商归零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": {// 创建新文件
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 地址和两字节的端口 ID
commandPORT();
}// DIR 命令 //接下来执行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() {
// 怎么说呢,其实很简单吧,应该就是把用户文件工作区拼上请求字符
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]:命令字符串的第二个 一般是参数
*/
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);
// 要输出的数据
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");
}
}
---------------------