简单实现javaftp服务器
来源:互联网 发布:java电子商务系统源码 编辑:程序博客网 时间:2024/06/10 02:12
<span style="font-family: Arial, Helvetica, sans-serif;"></span><pre name="code" class="java">class UserInfo{ String user; String password; String workDir;}
<span style="font-family: Arial, Helvetica, sans-serif;"> //监听21号端口,21口用于控制,20口用于传数据</span>
ServerSocket s = new ServerSocket(21); for(;;) { //接受客户端请求 Socket incoming = s.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(incoming.getInputStream())); PrintWriter out = new PrintWriter(incoming.getOutputStream(),true);//文本文本输出流 out.println("220 准备为您服务"+",你是当前第 "+counter+" 个登陆者!");//命令正确的提示 //创建服务线程 FtpHandler h = new FtpHandler(incoming,i); h.start(); users.add(h); //将此用户线程加入到这个 ArrayList 中 counter++; i++; }
class FtpHandler extends Thread{ Socket ctrlSocket; //用于控制的套接字 Socket dataSocket; //用于传输的套接字 int id; String cmd = ""; //存放指令(空格前) String param = ""; //放当前指令之后的参数(空格后) String user; String remoteHost = " "; //客户IP int remotePort = 0; //客户TCP 端口号 String dir = FtpServer.initDir;//当前目录 String rootdir = "c:/"; //默认根目录,在checkPASS中设置 int state = 0 ; //用户状态标识符,在checkPASS中设置 String reply; //返回报告 PrintWriter ctrlOutput; int type = 0; //文件类型(ascII 或 bin) String requestfile = ""; boolean isrest = false; //FtpHandler方法 //构造方法 public FtpHandler(Socket s,int i) { ctrlSocket = s; id = i; } //run 方法 public void run() { String str = ""; int parseResult; //与cmd 一一对应的号 try { BufferedReader ctrlInput = new BufferedReader (new InputStreamReader(ctrlSocket.getInputStream())); ctrlOutput = new PrintWriter(ctrlSocket.getOutputStream(),true); state = FtpState.FS_WAIT_LOGIN; //0 boolean finished = false; while(!finished) { str = ctrlInput.readLine(); /// if(str == null) finished = true; //跳出while else { parseResult = parseInput(str); //指令转化为指令号 System.out.println("指令:"+cmd+" 参数:"+param); System.out.print("->"); switch(state) //用户状态开关 { case FtpState.FS_WAIT_LOGIN: finished = commandUSER(); break; case FtpState.FS_WAIT_PASS: finished = commandPASS(); break; case FtpState.FS_LOGIN: { switch(parseResult)//指令号开关,决定程序是否继续运行的关键 { case -1: errCMD(); //语法错 break; case 4: finished = commandCDUP(); //到上一层目录 break; case 6: finished = commandCWD(); //到指定的目录 break; case 7: finished = commandQUIT(); //退出 break; case 9: finished = commandPORT(); //客户端IP:地址+TCP 端口号 break; case 11: finished = commandTYPE(); //文件类型设置(ascII 或 bin) break; case 14: finished = commandRETR(); //从服务器中获得文件 break; case 15: finished = commandSTOR(); //向服务器中发送文件 break; case 22: finished = commandABOR(); //关闭传输用连接dataSocket break; case 23: finished = commandDELE(); //删除服务器上的指定文件 break; case 25: finished = commandMKD(); //建立目录 break; case 27: finished = commandLIST(); //文件和目录的列表 break; case 26: case 33: finished = commandPWD(); //"当前目录" 信息 break; case 32: finished = commandNOOP(); //"命令正确" 信息 break; } } break; } } ctrlOutput.println(reply); ctrlOutput.flush();//////////////////////////////////// } ctrlSocket.close(); } catch(Exception e) { e.printStackTrace(); } } //parseInput方法 int parseInput(String s) { int p = 0; int i = -1; p = s.indexOf(" "); if(p == -1) //如果是无参数命令(无空格) cmd = s; else cmd = s.substring(0,p); //有参数命令,过滤参数 if(p >= s.length() || p ==-1)//如果无空格,或空格在读入的s串最后或之外 param = ""; else param = s.substring(p+1,s.length()); cmd = cmd.toUpperCase(); //转换该 String 为大写 if(cmd.equals("CDUP")) i = 4; if(cmd.equals("CWD")) i = 6; if(cmd.equals("QUIT")) i = 7; if(cmd.equals("PORT")) i = 9; if(cmd.equals("TYPE")) i = 11; if(cmd.equals("RETR")) i = 14; if(cmd.equals("STOR")) i = 15; if(cmd.equals("ABOR")) i = 22; if(cmd.equals("DELE")) i = 23; if(cmd.equals("MKD")) i = 25; if(cmd.equals("PWD")) i = 26; if(cmd.equals("LIST")) i = 27; if(cmd.equals("NOOP")) i = 32; if(cmd.equals("XPWD")) i = 33; return i; } //validatePath方法 //判断路径的属性,返回 int int validatePath(String s) { File f = new File(s); //相对路径 if(f.exists() && !f.isDirectory()) { String s1 = s.toLowerCase(); String s2 = rootdir.toLowerCase(); if(s1.startsWith(s2)) return 1; //文件存在且不是路径,且以rootdir 开始 else return 0; //文件存在且不是路径,不以rootdir 开始 } f = new File(addTail(dir)+s);//绝对路径 if(f.exists() && !f.isDirectory()) { String s1 = (addTail(dir)+s).toLowerCase(); String s2 = rootdir.toLowerCase(); if(s1.startsWith(s2)) return 2; //文件存在且不是路径,且以rootdir 开始 else return 0; //文件存在且不是路径,不以rootdir 开始 } return 0; //其他情况 } boolean checkPASS(String s) //检查密码是否正确,从文件中找 { for(int i = 0; i<FtpServer.usersInfo.size();i++) { if(((UserInfo)FtpServer.usersInfo.get(i)).user.equals(user) && ((UserInfo)FtpServer.usersInfo.get(i)).password.equals(s)) { rootdir = ((UserInfo)FtpServer.usersInfo.get(i)).workDir; dir = ((UserInfo)FtpServer.usersInfo.get(i)).workDir; return true; } } return false; } //commandUSER方法 //用户名是否正确 boolean commandUSER() { if(cmd.equals("USER")) { reply = "331 用户名正确,需要口令"; user = param; state = FtpState.FS_WAIT_PASS; return false; } else { reply = "501 参数语法错误,用户名不匹配"; return true; } } //commandPASS 方法 //密码是否正确 boolean commandPASS() { if(cmd.equals("PASS")) { if(checkPASS(param)) { reply = "230 用户登录了"; state = FtpState.FS_LOGIN; System.out.println("新消息: 用户: "+user+" 来自于: "+ remoteHost +"登录了"); System.out.print("->"); return false; } else { reply = "530 没有登录"; return true; } } else { reply = "501 参数语法错误,密码不匹配"; return true; } } void errCMD() { reply = "500 语法错误"; } boolean commandCDUP()//到上一层目录 { dir = FtpServer.initDir; File f = new File(dir); if(f.getParent()!=null &&(!dir.equals(rootdir)))//有父路径 && 不是根路径 { dir = f.getParent(); reply = "200 命令正确"; } else { reply = "550 当前目录无父路径"; } return false; }// commandCDUP() end boolean commandCWD()// CWD (CHANGE WORKING DIRECTORY) { //该命令改变工作目录到用户指定的目录 File f = new File(param); String s = ""; String s1 = ""; if(dir.endsWith("/")) s = dir; else s = dir + "/"; File f1 = new File(s+param); if(f.isDirectory() && f.exists()) { if(param.equals("..") || param.equals("..\\")) { if(dir.compareToIgnoreCase(rootdir)==0) { reply = "550 此路径不存在"; //return false; } else { s1 = new File(dir).getParent(); if(s1!=null) { dir = s1; reply = "250 请求的文件处理结束, 当前目录变为: "+dir; } else reply = "550 此路径不存在"; } } else if(param.equals(".") || param.equals(".\\")) {} else { dir = param; reply = "250 请求的文件处理结束, 工作路径变为 "+dir; } } else if(f1.isDirectory() && f1.exists()) { dir = s+param; reply = "250 请求的文件处理结束, 工作路径变为 "+dir; } else reply = "501 参数语法错误"; return false; } // commandCDW() end boolean commandQUIT() { reply = "221 服务关闭连接"; return true; }// commandQuit() end /*使用该命令时,客户端必须发送客户端用于接收数据的32位IP 地址和16位 的TCP 端口号。 *这些信息以8位为一组,使用十进制传输,中间用逗号隔开。 */ boolean commandPORT() { int p1 = 0; int p2 = 0; int[] a = new int[6];//存放ip+tcp int i = 0; // try { while((p2 = param.indexOf(",",p1))!=-1)//前5位 { a[i] = Integer.parseInt(param.substring(p1,p2)); p2 = p2+1; p1 = p2; i++; } a[i] = Integer.parseInt(param.substring(p1,param.length()));//最后一位 } catch(NumberFormatException e) { reply = "501 参数语法错误"; return false; } remoteHost = a[0]+"."+a[1]+"."+a[2]+"."+a[3]; remotePort = a[4] * 256+a[5]; reply = "200 命令正确"; return false; }//commandPort() end /*LIST 命令用于向客户端返回服务器中工作目录下的目录结构,包括文件和目录的列表。 *处理这个命令时,先创建一个临时的套接字向客户端发送目录信息。这个套接字的目的 *端口号缺省为,然后为当前工作目录创建File 对象,利用该对象的list()方法得到一 *个包含该目录下所有文件和子目录名称的字符串数组,然后根据名称中是否含有文件名 *中特有的"."来区别目录和文件。最后,将得到的名称数组通过临时套接字发送到客户端。 **/ boolean commandLIST()//文件和目录的列表 { try { dataSocket = new Socket(remoteHost,remotePort,InetAddress.getLocalHost(),20); PrintWriter dout = new PrintWriter(dataSocket.getOutputStream(),true); if(param.equals("") || param.equals("LIST")) { ctrlOutput.println("150 文件状态正常,ls以 ASCII 方式操作"); File f = new File(dir); String[] dirStructure = f.list();//指定路径中的文件名数组,不包括当前路径或父路径 String fileType; for(int i =0; i<dirStructure.length;i++) { if(dirStructure[i].indexOf(".")!=-1) { fileType = "- "; //父目录(在linux下) } else { fileType = "d "; //本目录的文件和子目录 } dout.println(dirStructure[i]);//(fileType+dirStructure[i]); } } dout.close(); dataSocket.close(); reply = "226 传输数据连接结束"; } catch(Exception e) { e.printStackTrace(); reply = "451 Requested action aborted: local error in processing"; return false; } return false; }// commandLIST() end boolean commandTYPE() //TYPE 命令用来完成类型设置 { if(param.equals("A")) { type = FtpState.FTYPE_ASCII;//0 reply = "200 命令正确 ,转 ASCII 模式"; } else if(param.equals("I")) { type = FtpState.FTYPE_IMAGE;//1 reply = "200 命令正确 转 BINARY 模式"; } else reply = "504 命令不能执行这种参数"; return false; } //connamdRETR 方法 //从服务器中获得文件 boolean commandRETR() { requestfile = param; File f = new File(requestfile); if(!f.exists()) { f = new File(addTail(dir)+param); if(!f.exists()) { reply = "550 文件不存在"; return false; } requestfile = addTail(dir)+param; } if(isrest) { } else { if(type==FtpState.FTYPE_IMAGE) //bin { try { ctrlOutput.println("150 文件状态正常,以二进治方式打开文件: "+ requestfile); dataSocket = new Socket(remoteHost,remotePort,InetAddress.getLocalHost(),20); BufferedInputStream fin = new BufferedInputStream(new FileInputStream(requestfile)); PrintStream dataOutput = new PrintStream(dataSocket.getOutputStream(),true); byte[] buf = new byte[1024]; //目标缓冲区 int l = 0; while((l=fin.read(buf,0,1024))!=-1) //缓冲区未读满 { dataOutput.write(buf,0,l); //写入套接字 } fin.close(); dataOutput.close(); dataSocket.close(); reply ="226 传输数据连接结束"; } catch(Exception e) { e.printStackTrace(); reply = "451 请求失败: 传输出故障"; return false; } } if(type==FtpState.FTYPE_ASCII)//ascII { try { ctrlOutput.println("150 Opening ASCII mode data connection for "+ requestfile); dataSocket = new Socket(remoteHost,remotePort,InetAddress.getLocalHost(),20); BufferedReader fin = new BufferedReader(new FileReader(requestfile)); PrintWriter dataOutput = new PrintWriter(dataSocket.getOutputStream(),true); String s; while((s=fin.readLine())!=null) { dataOutput.println(s); ///??? } fin.close(); dataOutput.close(); dataSocket.close(); reply ="226 传输数据连接结束"; } catch(Exception e) { e.printStackTrace(); reply = "451 请求失败: 传输出故障"; return false; } } } return false; } //commandSTOR 方法 //向服务器中发送文件STOR boolean commandSTOR() { if(param.equals("")) { reply = "501 参数语法错误"; return false; } requestfile = addTail(dir)+param; if(type == FtpState.FTYPE_IMAGE)//bin { try { ctrlOutput.println("150 Opening Binary mode data connection for "+ requestfile); dataSocket = new Socket(remoteHost,remotePort,InetAddress.getLocalHost(),20); BufferedOutputStream fout = new BufferedOutputStream(new FileOutputStream(requestfile)); BufferedInputStream dataInput = new BufferedInputStream(dataSocket.getInputStream()); byte[] buf = new byte[1024]; int l = 0; while((l = dataInput.read(buf,0,1024))!=-1) { fout.write(buf,0,l); } dataInput.close(); fout.close(); dataSocket.close(); reply = "226 传输数据连接结束"; } catch(Exception e) { e.printStackTrace(); reply = "451 请求失败: 传输出故障"; return false; } } if(type == FtpState.FTYPE_ASCII)//ascII { try { ctrlOutput.println("150 Opening ASCII mode data connection for "+ requestfile); dataSocket = new Socket(remoteHost,remotePort,InetAddress.getLocalHost(),20); PrintWriter fout = new PrintWriter(new FileOutputStream(requestfile)); BufferedReader dataInput = new BufferedReader(new InputStreamReader(dataSocket.getInputStream())); String line; while((line = dataInput.readLine())!=null) { fout.println(line); } dataInput.close(); fout.close(); dataSocket.close(); reply = "226 传输数据连接结束"; } catch(Exception e) { e.printStackTrace(); reply = "451 请求失败: 传输出故障"; return false; } } return false; } boolean commandPWD() { reply = "257 " + dir + " 是当前目录."; return false; } boolean commandNOOP() { reply = "200 命令正确."; return false; } //强关dataSocket 流 boolean commandABOR() { try { dataSocket.close(); } catch(Exception e) { e.printStackTrace(); reply = "451 请求失败: 传输出故障"; return false; } reply = "421 服务不可用, 关闭数据传送连接"; return false; } //删除服务器上的指定文件 boolean commandDELE() { int i = validatePath(param); if(i == 0) { reply = "550 请求的动作未执行,文件不存在,或目录不对,或其他"; return false; } if(i == 1) { File f = new File(param); f.delete(); } if(i == 2) { File f= new File(addTail(dir)+param); f.delete(); } reply = "250 请求的文件处理结束,成功删除服务器上文件"; return false; } //建立目录,要绝对路径 boolean commandMKD() { String s1 = param.toLowerCase(); String s2 = rootdir.toLowerCase(); if(s1.startsWith(s2)) { File f = new File(param); if(f.exists()) { reply = "550 请求的动作未执行,目录已存在"; return false; } else { f.mkdirs(); reply = "250 请求的文件处理结束, 目录建立"; } } else { File f = new File(addTail(dir)+param); if(f.exists()) { reply = "550 请求的动作未执行,目录已存在"; return false; } else { f.mkdirs(); reply = "250 请求的文件处理结束, 目录建立"; } } return false; } String addTail(String s) { if(!s.endsWith("/")) s = s + "/"; return s; } }
/***************************************************************************/class FtpState{ final static int FS_WAIT_LOGIN = 0; //等待输入用户名状态 final static int FS_WAIT_PASS = 1; //等待输入密码状态 final static int FS_LOGIN = 2; //已经登陆状态 final static int FTYPE_ASCII = 0; final static int FTYPE_IMAGE = 1; final static int FMODE_STREAM = 0; final static int FMODE_COMPRESSED = 1; final static int FSTRU_FILE = 0; final static int FSTRU_PAGE = 1;}
0 0
- 简单实现javaftp服务器
- JavaFTP文件传输 简单实现
- 使用Apache Commons Net包实现javaFTP来上传目录
- 使用Apache Commons Net包实现javaFTP来上传目录
- 使用Apache Commons Net包实现javaFTP来上传目录
- javaftp上传下载
- 简单HTTP服务器实现
- select服务器简单实现
- 简单实现服务器
- 请问哪位高手知道用Apache Commons Net包实现javaFTP上传整个目录(文件夹)
- 使用Apache Commons Net包中的FTPClient实现javaFTP来上传目录
- 使用Apache Commons Net包中的FTPClient实现javaFTP来上传目录(新)
- 使用Apache Commons Net包中的FTPClient实现javaFTP来上传目录(新)
- C#实现简单WEB服务器
- C#实现简单WEB服务器
- 简单的web服务器实现
- VC++实现简单HTTP服务器
- linux实现简单 PPPOE服务器
- 5-22 龟兔赛跑 (20分) C语言版
- poj 2823 滑动窗口 单调队列
- Java基础-强引用、弱引用、软引用、虚引用
- linux php imagick 安装
- VirtualBox中安装CentOS5.5
- 简单实现javaftp服务器
- BZOJ-1879 Bill的挑战 状态压缩DP
- nf51822 ---看门狗(WDT)
- 安卓基础:自定义控件实现ViewPager指示器
- File类通过递归列出目录的结构
- hdu2079选课时间(背包)
- DOM事件处理程序学习随笔1(IMOOC)
- 设计模式——装饰者模式
- 关于在servlet和action中返回json数据的一些问题