FTP 命令 
h` g2P  "L;x1!" }    FTP 的主要操作都是基于各种命令基础之上的。常用的命令有: 
MUf`VS;*  IQ [19FF}    · 设置传输模式,它包括ASCⅡ(文本) 和BINARY 二进制模式; 
t.^o/*|Gz  '7kP@!^t    · 目录操作,改变或显示远程计算机的当前目录(cd、dir/ls 命令); 
_g_XTD  Acq[~64('    · 连接操作,open命令用于建立同远程计算机的连接;close命令用于关闭连接; 
S<Ew,e7wr  wBX%g     · 发送操作,put命令用于传送文件到远程计算机;mput 命令用于传送多个文件到远程计算机; 
y3 L5q<  'Gvx?>CY    · 获取操作,get命令用于接收一个文件;mget命令用于接收多个文件。 
],Fl __  =aU , U    编程思路 
Zs]<^_$  Vy`X l    根据FTP 的工作原理,在主函数中建立一个服务器套接字端口,等待客户端请求,一旦客户端请求被接受,服务器程序就建立一个服务器分线程,处理客户端的命令。如果客户端需要和服务器端进行文件的传输,则建立一个新的套接字连接来完成文件的操作。 
vM^H6,i{  at7 Un%    编程技巧说明 
+-V4f  3 <MO"Wb    1.主函数设计 
r#"}PfS8  y<av5D+{Z    在主函数中,完成服务器端口的侦听和服务线程的创建。我们利用一个静态字符串变量initDir 来保存服务器线程运行时所在的工作目录。服务器的初始工作目录是由程序运行时用户输入的,缺省为C盘的根目录。 
pF;IjAS  SLYQaTbpC    具体的代码如下: 
E_~^Z.]  uDq"$[z    public class ftpServer extends Thread{ 
5!dW,ro    private Socket socketClient; 
A+$qOz)^    private int counter; 
|/n+hfKEvB    private static String initDir; 
d]k>E?K    public static void main(String[] args){ 
3iYToNc<1    if(args.length != 0) { 
5 KVPX,FhI     initDir = args[0]; 
| /fb/aX:    }else{ initDir = "c:";} 
J\( \F    int i = 1; 
atYLt(b]    try{ 
& R i0     System.out.println("ftp server started!"); 
m5"?t >{     //监听21号端口 
geQ+ v     ServerSocket s = new ServerSocket(21); 
V:i{,Q     for(;;){ 
3>BD&fWF      //接受客户端请求 
{=u%B'?W      Socket incoming = s.accept(); 
H`| o\5%.S      //创建服务线程 
>j6%_0!Y0B      new ftpServer(incoming,i).start(); 
-SQLo^uU      i++; 
dB6+ J(     } 
hs 4K)(&    }catch(Exception e){} 
M yQSfWx.    } 
UC5,k@az]  kXjb6PYaO    2. 线程类的设计 
#~~!GNlxb  c,6K8= (    线程类的主要设计都是在run()方法中实现。用run()方法得到客户端的套接字信息,根据套接字得到输入流和输出流,向客户端发送欢迎信息。 
-t8$&!wmw  z4[t&Hlxc    3. FTP 命令的处理 
mZk*4.  m"tq #    (1) 访问控制命令 
r5Qv^FQS  m%Xmn_ <N1    · user name(user) 和 password (pass) 命令处理代码如下: 
<#D:5`d  co FSPA^P    if(str.startsWith("USER")){ 
mWSzH#g    user = str.substring(4); 
?H7UBU<R    user = user.trim(); 
Wc]~>Yl_    out.println("331 Password"); 
m?!~(%NM    } 
`2'bP,bK8O    if(str.startsWith("PASS")) 
/eSI>n:    out.println("230 User "+user+" logged in."); 
<-\5L L76+  |~zKn!YB    User 命令和 Password 命令分别用来提交客户端用户输入的用户名和口令。 
ld/GTvFtN  g2t5*pv_    · CWD (CHANGE WORKING DIRECTORY) 命令处理代码如下: 
}\Lg(@$O  lTN*4J4O0    if(str.startsWith("CWD")){ 
2 HgX.Uk;~    String str1 = str.substring(3); 
f3g` _O.?    dir = dir+"/"+str1.trim(); 
$%*TyLE    out.println("250 CWD command succesful"); 
C' v1+:    } 
8 \Y+Y PW  qSc1'+     该命令改变工作目录到用户指定的目录。 
:J}sm/SM  ns|vW    · CDUP (CHANGE TO PARENT DIRECTORY) 命令处理代码如下: 
~;O('\  /=KQs~ /    if(str.startsWith("CDUP")){ 
"yi(E    int n = dir.lastIndexOf("/"); 
yWw 1l~    dir = dir.substring(0,n); 
h[$wH!X`J    out.println("250 CWD command succesful"); 
%Vr4%,X3L    } 
"1c-$52  xp`C E\M    该命令改变当前目录为上一层目录。 
& WR8`*o  K "8<mv(    · QUIT命令处理代码如下: 
lT\Rj  $z1[+.    if(str.startsWith("QUIT")) { 
5:F#3,I    out.println("GOOD BYE"); 
H;SY;    done = true; 
v-]Y_3:\t    } 
o861;..  6PkW 3?_    该命令退出及关闭与服务器的连接,输出GOOD BYE。 
I.? T  /I\;)o=s8    (2) 传输参数命令 
/2ky!zd:  4P8Zw}#    · Port命令处理代码如下: 
+3 P:G21  ! %*6mzP    if(str.startsWith("PORT")) { 
)D]JCjseQ    out.println("200 PORT command successful"); 
w7M *qAm    int i = str.length() - 1; 
{92-io?    int j = str.lastIndexOf(","); 
Pu-/*h,    int k = str.lastIndexOf(",",j-1); 
aFv([a Y    String str1,str2; 
4)9a[o]e-    str1=""; 
k+&w'|    str2=""; 
JcN],0x<    for(int l=k+1;lstr1 = str2 + str.charAt(l); 
vtnY.>e-,    } 
i;*=!Bt    for(int l=j+1;l<=i;l++){ 
GZf 2cd%    str2 = str2 + str.charAt(l); 
Ih%G$>B    } 
KtJw8j    tempPort = Integer.parseInt(str1) * 16 *16 +Integer.parseInt(str2); 
t/8@ %n.7    } 
9 */Bat  A *>\:B    使用该命令时,客户端必须发送客户端用于接收数据的32位IP 地址和16位 的TCP 端口号。这些信息以8位为一组,使用十进制传输,中间用逗号隔开。 
%/LfBgi(  :-OxJE    · TYPE命令处理代码如下: 
7{4@"$Dn*f  of&6UP9b    if(str.startsWith("TYPE")){ 
I,NX|jT    out.println("200 type set"); 
bYIxN~0TI    } 
]z6eyp?U-  :]]({A),    TYPE 命令用来完成类型设置。 
dwWnTR  ^q1^^g [    (3) FTP 服务命令 
wYF 6RA  -u)&    · RETR (RETEIEVE) 和 STORE (STORE)命令处理的代码 
)SJ2gD  ?hl8=9xX    if(str.startsWith("RETR")){ 
sU:.tWt    out.println("150 Binary data connection"); 
5 7>}`H    str = str.substring(4); 
'-k0@YUjS-    str = str.trim(); 
h'^>XlD    RandomAccessFile outFile = new 
Je:O[* qB|    RandomAccessFile(dir+"/"+str,"r"); 
k5[AI5z$    Socket tempSocket = new Socket(host,tempPort); 
u$HlzqoN    OutputStream outSocket = tempSocket.getOutputStream(); 
'tUnlR=0'    byte byteBuffer[]= new byte[1024]; 
-[$n1\Yd2\    int amount; 
6aJ|Oa 9    try{ 
w+S %y,    while((amount = outFile.read(byteBuffer)) != -1){ 
eTK82hOef     outSocket.write(byteBuffer, 0, amount); 
~&]_2jI}bs    } 
n4oaLW82    outSocket.close(); 
]-hk')    out.println("226 transfer complete"); 
qO9vPSXjR    outFile.close(); 
s =_@lpN    tempSocket.close(); 
%PF\vvjO    } 
VeX9!!     catch(IOException e){} 
M^[VTk#|    } 
F Q&d {e    if(str.startsWith("STOR")){ 
{FK}ka.    out.println("150 Binary data connection"); 
5bD1     str = str.substring(4); 
;z)C    str = str.trim(); 
-9 ;dQjT    RandomAccessFile inFile = new 
J 2%7+U/    RandomAccessFile(dir+"/"+str,"rw"); 
t6q^B?-    Socket tempSocket = new Socket(host,tempPort); 
T\N<]y'-,    InputStream inSocket = tempSocket.getInputStream(); 
R~bSiM0jQ    byte byteBuffer[] = new byte[1024]; 
2asc xXI    int amount; 
vnWO_    try{ 
dQ6`jNp2y    while((amount =inSocket.read(byteBuffer) )!= -1){ 
$fAi(NtIF    inFile.write(byteBuffer, 0, amount); 
/ #/1,e_%    } 
kMn251(    inSocket.close(); 
5fT/2ZDc    out.println("226 transfer complete"); 
%-rG'+tV    inFile.close(); 
D!wsd.m    tempSocket.close(); 
WwSQvOC@J    } 
_DB$z>0    catch(IOException e){} 
=+j]Tm@ Y    } 
ofbiFWo_4P  0}` DqT    文件传输命令包括从服务器中获得文件RETR和向服务器中发送文件STOR,这两个命令的处理非常类似。处理RETR命令时,首先得到用户要获得的文件的名称,根据名称创建一个文件输入流,然后和客户端建立临时套接字连接,并得到一个输出流。随后,将文件输入流中的数据读出并借助于套接字输出流发送到客户端,传输完毕以后,关闭流和临时套接字。 
uW:i'fEb  qjBWU`8>=    STOR 命令的处理也是同样的过程,只是方向正好相反。 
#K`HLa])}  .I;r.<    · DELE (DELETE)命令处理代码如下: 
k%4Z- 8=)I  |6vJjWqHSM    if(str.startsWith("DELE")){ 
x ]1~ 0w    str = str.substring(4); 
B9WQ*r'    str = str.trim(); 
* a 5    File file = new File(dir,str); 
^5+AwK    boolean del = file.delete(); 
/{n@s}pW0Z    out.println("250 delete command successful"); 
{Yv<2J    } 
y&DD7pB+`  mN y=#O x~    DELE 命令用于删除服务器上的指定文件。 
z%T4l3CW  `+yXz3IX    · LIST命令处理代码如下: 
!g.\2zKg  5 U-u>Bq    if(str.startsWith("LIST")) { 
HEC+ 07C`    try{ 
4Fg)^YQn    out.println("150 ASCII data"); 
k}+6 }R Q    Socket tempSocket = new Socket(host,tempPort); 
Zx 'RK \    PrintWriter out2= new PrintWriter(tempSocket.getOutputStream(),true); 
p\W?|wjl    File file = new File(dir); 
=z b~ %    String[] dirStructure = new String; 
%@$2H!U}5    dirStructure= file.list(); 
r<Qmb,?qk    String strType=""; 
L[rN    for(int i=0;iif( dirStructure
.indexOf(".") == -1) { strType = "d ";} 1@ lf'#+  
   else r927nTTbV  
   {strType = "- ";} <^\K;(  
   out2.println(strType+dirStructure); _:coBMuC  
  } YkTa|fmE  
  tempSocket.close(); rY,U4i.  
  out.println("226 transfer complete"); vk^#P.7<  
  } HZSAy=4P  
  catch(IOException e){} ,mH{efDaC  
Smc<!mO~g  
  LIST 命令用于向客户端返回服务器中工作目录下的目录结构,包括文件和目录的列表。处理这个命令时,先创建一个临时的套接字向客户端发送目录信息。这个套接字的目的端口号缺省为1,然后为当前工作目录创建File 对象,利用该对象的list()方法得到一个包含该目录下所有文件和子目录名称的字符串数组,然后根据名称中是否含有文件名中特有的“.”来区别目录和文件。最后,将得到的名称数组通过临时套接字发送到客户端。查看本文来源