科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件用Java实现FTP服务器解决方案

用Java实现FTP服务器解决方案

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

用Java实现FTP服务器解决方案

作者:jiaolisd 来源:赛迪网技术社区 2007年12月1日

关键字: ftp 解决方案 服务器

  • 评论
  • 分享微博
  • 分享邮件
中国教程网 作者:nankailz…   zhdtP(tPMq  
{~36%U fN  
  FTP 命令 Kq {Ab  
 w)6CRR  
  FTP 的主要操作都是基于各种命令基础之上的。常用的命令有: {sGaW5 G%  
ev^3/hz  
  · 设置传输模式,它包括ASCⅡ(文本) 和BINARY 二进制模式; :VT_ =.#  
Itmmon  
  · 目录操作,改变或显示远程计算机的当前目录(cd、dir/ls 命令); A[^Lz  
NOlx`m\v  
  · 连接操作,open命令用于建立同远程计算机的连接;close命令用于关闭连接; HQwFpIH  
jv6Ni]U[[8  
  · 发送操作,put命令用于传送文件到远程计算机;mput 命令用于传送多个文件到远程计算机; j4Nk2| E  
oHr} xS,-  
  · 获取操作,get命令用于接收一个文件;mget命令用于接收多个文件。 B4J'MgI'HK  
D I] W  
  编程思路 [$WU~ [  
x4$+/~6A\F  
  根据FTP 的工作原理,在主函数中建立一个服务器套接字端口,等待客户端请求,一旦客户端请求被接受,服务器程序就建立一个服务器分线程,处理客户端的命令。如果客户端需要和服务器端进行文件的传输,则建立一个新的套接字连接来完成文件的操作。 c1%d>x  
>VzgS`mD  
  编程技巧说明 sx }kK dFS  
eXvLTY-@k  
  1.主函数设计 }I h =)  
h Sv8/UvI  
  在主函数中,完成服务器端口的侦听和服务线程的创建。我们利用一个静态字符串变量initDir 来保存服务器线程运行时所在的工作目录。服务器的初始工作目录是由程序运行时用户输入的,缺省为C盘的根目录。 y';goBH;j}  
lyfy =UT  
  具体的代码如下: _FS/}o8HW  
qTfx\)Tf  
  public class ftpServer extends Thread{ 7vrgR]-<  
  private Socket socketClient; _^FYJR|B  
  private int counter; 22avk>d)  
  private static String initDir; VastUSy7q  
  public static void main(String[] args){ aUmyJI8=:X  
  if(args.length != 0) { k5* QP1/  
   initDir = args[0]; ~ZeTU{~8  
  }else{ initDir = "c:";} *!av(2za  
  int i = 1; v!3RR2(?  
  try{ `2aU0*xeu  
   System.out.println("ftp server started!"); JLX|1z II  
   //监听21号端口 Z*:^U{.Bz  
   ServerSocket s = new ServerSocket(21); i43pJS&r  
   for(;;){ ,BAqUQ  
    //接受客户端请求 q3>+ dsV  
    Socket incoming = s.accept(); ;B#!B Q  
    //创建服务线程 6e.Rt `;)  
    new ftpServer(incoming,i).start(); "x +<$>  
    i++; jG Y/0AB  
   } >htH.gLw  
  }catch(Exception e){} ?k)J   
  } TGvTi!!t  
KNUuW=0  
  2. 线程类的设计 P}:iJds  
_m}5oto  
  线程类的主要设计都是在run()方法中实现。用run()方法得到客户端的套接字信息,根据套接字得到输入流和输出流,向客户端发送欢迎信息。 ,$Qf.y  
k"8J_HH  
  3. FTP 命令的处理 A9]<IKM,o  
CkmT<9  
  (1) 访问控制命令 hr<Y1QAA  
6jIW0D  
  · user name(user) 和 password (pass) 命令处理代码如下: QJ<^=IlH)  
.Oep1R?  
  if(str.startsWith("USER")){ Z Y9NJ_\,]  
  user = str.substring(4); M!F/8=PU8  
  user = user.trim(); &jcn 0U  
  out.println("331 Password");  bZr0s#~  
  } =-m&bHV5y  
  if(str.startsWith("PASS")) #qN6G0  
  out.println("230 User "+user+" logged in."); EZtNO2p3^  
RXP6eCV M  
  User 命令和 Password 命令分别用来提交客户端用户输入的用户名和口令。 TxVO~x#h  
=D5@TH  
  · CWD (CHANGE WORKING DIRECTORY) 命令处理代码如下: c0$lGu  
MC"!~J  
  if(str.startsWith("CWD")){ {N, 1C@!!  
  String str1 = str.substring(3); +fpka   
  dir = dir+"/"+str1.trim(); ;v' {lj  
  out.println("250 CWD command succesful"); <PEJK=\z  
  } @x O[ 9k  
p-ooq{P  
  该命令改变工作目录到用户指定的目录。 UNNmgg  
a?YjAqb%  
  · CDUP (CHANGE TO PARENT DIRECTORY) 命令处理代码如下: GO D\2>gY  
?"%U|E  
  if(str.startsWith("CDUP")){ `"+_GnPI  
  int n = dir.lastIndexOf("/"); `s/E^s]w  
  dir = dir.substring(0,n); "0 =y#A{  
  out.println("250 CWD command succesful"); 0S2p88B  
  } G9z=Fg\-,  
'7 % 0#  
  该命令改变当前目录为上一层目录。 Q>s_>@  
Jw[d4KJz`  
  · QUIT命令处理代码如下: &q^aL^aj  
l*? Ha  
  if(str.startsWith("QUIT")) { CpTr s2ON  
  out.println("GOOD BYE"); o!M*IX{,  
  done = true; >Fhw< Il t  
  } :#&l  
3# B+ Tk  
  该命令退出及关闭与服务器的连接,输出GOOD BYE。 C{[+7~n|   
PKfjdkn'  
  (2) 传输参数命令 (T[LA2]  
D!=q3"[  
  · Port命令处理代码如下: 8u?}Pq5  
nxk)'9 xz  
  if(str.startsWith("PORT")) { QdMNh-vOx  
  out.println("200 PORT command successful"); o]c7zZ~  
  int i = str.length() - 1; edE$ejU3  
  int j = str.lastIndexOf(","); /B{DXOH  
  int k = str.lastIndexOf(",",j-1); 7J 2m &?  
  String str1,str2; kwW\<5K%A  
  str1=""; kGgeJ aW  
  str2=""; (p^O>wv  
  for(int l=k+1;lstr1 = str2 + str.charAt(l); f1MV,C/3A  
  } RdC4+h}  
  for(int l=j+1;l<=i;l++){ RW;ABKBV>  
  str2 = str2 + str.charAt(l); WGu8R m_  
  } 3+ja1 {l  
  tempPort = Integer.parseInt(str1) * 16 *16 +Integer.parseInt(str2); *Ff.[-1Y  
  } ;nsorK&#c  
d/b+a5  
  使用该命令时,客户端必须发送客户端用于接收数据的32位IP 地址和16位 的TCP 端口号。这些信息以8位为一组,使用十进制传输,中间用逗号隔开。 O5+L`1;  
o!dX6aJ$  
  · TYPE命令处理代码如下: EEd0QBiz  
tnA cX '(h  
  if(str.startsWith("TYPE")){ ZkB7r[XIv'  
  out.println("200 type set"); F-rP na  
  } %)0 I  
MTpW&{juX  
  TYPE 命令用来完成类型设置。 vGq;v?o4  
%?)'dM73`  
  (3) FTP 服务命令 hS'L5  
 @%,b  
  · RETR (RETEIEVE) 和 STORE (STORE)命令处理的代码 :X\ hte  
`+vP  
  if(str.startsWith("RETR")){ dla 9qp3  
  out.println("150 Binary data connection"); yv /uTR  
  str = str.substring(4); YN+E |xq  
  str = str.trim(); ]5Te.{K\  
  RandomAccessFile outFile = new !Dv@btUD  
  RandomAccessFile(dir+"/"+str,"r"); h jf@wB  
  Socket tempSocket = new Socket(host,tempPort); [.TUZ^{c)  
  OutputStream outSocket = tempSocket.getOutputStream(); h lGzR% 7  
  byte byteBuffer[]= new byte[1024]; P5g!+l6^  
  int amount; 2qn440nX  
  try{ qpG|e<m/  
  while((amount = outFile.read(byteBuffer)) != -1){ ,kOK`B8PR  
   outSocket.write(byteBuffer, 0, amount); CI=oX[yyG  
  } :2T]gWU  
  outSocket.close(); MnJabY'  
  out.println("226 transfer complete"); `dj j  
  outFile.close(); SN'Z+a  
  tempSocket.close(); 3?qr7sn  
  } 9>jGuUT  
  catch(IOException e){} *C\$rxv  
  } w,h,f  
  if(str.startsWith("STOR")){ g\Q&WF_\ y  
  out.println("150 Binary data connection"); ^]MGc  
  str = str.substring(4); Kq14 }  
  str = str.trim(); c9zHgv6  
  RandomAccessFile inFile = new ]hcE"o\}  
  RandomAccessFile(dir+"/"+str,"rw"); GW$G`p"  
  Socket tempSocket = new Socket(host,tempPort); :f sNays  
  InputStream inSocket = tempSocket.getInputStream(); ;$k<Fd  
  byte byteBuffer[] = new byte[1024]; P=Q|eWO)  
  int amount; hOe5Zoz.J/  
  try{ \T?4DI  
  while((amount =inSocket.read(byteBuffer) )!= -1){ D}<hIgM  
  inFile.write(byteBuffer, 0, amount); MsSlu8l  
  } &OH`F>  
  inSocket.close(); S([(WtunGx  
  out.println("226 transfer complete"); :P%5B&us  
  inFile.close(); aMY cn"Y  
  tempSocket.close(); K/M@9*b  
  } u`HX?]G~  
  catch(IOException e){} U2 VZr;  
  } B gJ2tkR!(  
xVp~  
  文件传输命令包括从服务器中获得文件RETR和向服务器中发送文件STOR,这两个命令的处理非常类似。处理RETR命令时,首先得到用户要获得的文件的名称,根据名称创建一个文件输入流,然后和客户端建立临时套接字连接,并得到一个输出流。随后,将文件输入流中的数据读出并借助于套接字输出流发送到客户端,传输完毕以后,关闭流和临时套接字。 uh9%8f  
O56O\2EO+{  
  STOR 命令的处理也是同样的过程,只是方向正好相反。 g=`W_QI  
B+aGqVa M  
  · DELE (DELETE)命令处理代码如下: tB84)s7f  
Xg#7S+P  
  if(str.startsWith("DELE")){ t0u;z\  
  str = str.substring(4); Xp}!z~u  
  str = str.trim(); ND+P:? Z  
  File file = new File(dir,str); -T=Tpr  
  boolean del = file.delete(); `Z`H5\Mt  
  out.println("250 delete command successful"); ~g9[3]q?  
  } * `0`2f  
LCR|Z6!r  
  DELE 命令用于删除服务器上的指定文件。 SQ[Ho%KB  
imPXoAeH]{  
  · LIST命令处理代码如下: ,Bv'` <  
SKZ?S!m  
  if(str.startsWith("LIST")) { 0 jgC@ w  
  try{ 5_6ITlKt  
  out.println("150 ASCII data"); 3I%sP d@R  
  Socket tempSocket = new Socket(host,tempPort); XW) =jZ]o  
  PrintWriter out2= new PrintWriter(tempSocket.getOutputStream(),true); R2aW5KsNF  
  File file = new File(dir); N.=U;@+  
  String[] dirStructure = new String; @^2OSP@  
  dirStructure= file.list(); b/${hr%Q!  
  String strType=""; bhi( m Mp  
  for(int i=0;iif( dirStructure.indexOf(".") == -1) { strType = "d ";} Q,W0ZS b){  
   else 8c(WAP  
   {strType = "- ";} dp%sOA)Yw  
   out2.println(strType+dirStructure); (a}8[xs;  
  } 'Q<r. p# %  
  tempSocket.close(); HrTV ^#iE  
  out.println("226 transfer complete"); (xvY/WO  
  } Kr}#uAz u  
  catch(IOException e){} PQ<U) K  
u1!a["u  
  LIST 命令用于向客户端返回服务器中工作目录下的目录结构,包括文件和目录的列表。处理这个命令时,先创建一个临时的套接字向客户端发送目录信息。这个套接字的目的端口号缺省为1,然后为当前工作目录创建File 对象,利用该对象的list()方法得到一个包含该目录下所有文件和子目录名称的字符串数组,然后根据名称中是否含有文件名中特有的“.”来区别目录和文件。最后,将得到的名称数组通过临时套接字发送到客户端。
 
 
查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章