1 /* 2 FTPFactory.cs 3 Better view with tab space=4 4 Written by Jaimon Mathew (jaimonmathew@rediffmail.com) 5 Rolander,Dan (Dan.Rolander@marriott.com) has modified the 6 download 7 method to cope with file name with path information. He also 8 provided 9 the XML comments so that the library provides Intellisense 10 descriptions. 11 use the following line to compile 12 csc /target:library /out:FTPLib.dll /r:System.DLL FTPFactory.cs 13 */ 14 using System; 15 using System.Net; 16 using System.IO; 17 using System.Text; 18 using System.Net.Sockets; 19 namespace WindowsApplication1 20 ...{ 21 public class FTPFactory 22 ...{ 23 private string 24 remoteHost,remotePath,remoteUser,remotePass,mes; 25 private int remotePort,bytes; 26 private Socket clientSocket; 27 private int retValue; 28 private Boolean debug; 29 private Boolean logined; 30 private string reply; 31 private static int BLOCK_SIZE = 512; 32 Byte[] buffer = new Byte[BLOCK_SIZE]; 33 Encoding ASCII = Encoding.ASCII; 34 public FTPFactory() 35 ...{ 36 remoteHost = "localhost"; 37 remotePath = "."; 38 remoteUser = "anonymous"; 39 remotePass = "jaimon@school2000.co.uk"; 40 remotePort = 21; 41 debug = false; 42 logined = false; 43 } 44 /**//// 45 /// Set the name of the FTP server to connect to. 46 /// 47 /// Server name 48 public void setRemoteHost(string remoteHost) 49 ...{ 50 this.remoteHost = remoteHost; 51 } 52 /**//// 53 /// Return the name of the current FTP server. 54 /// 55 /// Server name 56 public string getRemoteHost() 57 ...{ 58 return remoteHost; 59 } 60 /**//// 61 /// Set the port number to use for FTP. 62 /// 63 /// Port number 64 public void setRemotePort(int remotePort) 65 ...{ 66 this.remotePort = remotePort; 67 } 68 /**//// 69 /// Return the current port number. 70 /// 71 /// Current port number 72 public int getRemotePort() 73 ...{ 74 return remotePort; 75 } 76 /**//// 77 /// Set the remote directory path. 78 /// 79 /// The remote directory path 80 public void setRemotePath(string remotePath) 81 ...{ 82 this.remotePath = remotePath; 83 } 84 /**//// 85 /// Return the current remote directory path. 86 /// 87 /// The current remote directory path. 88 public string getRemotePath() 89 ...{ 90 return remotePath; 91 } 92 /**//// 93 /// Set the user name to use for logging into the remote server. 94 /// 95 /// Username 96 public void setRemoteUser(string remoteUser) 97 ...{ 98 this.remoteUser = remoteUser; 99 } 100 /**//// 101 /// Set the password to user for logging into the remote server. 102 /// 103 /// Password 104 public void setRemotePass(string remotePass) 105 ...{ 106 this.remotePass = remotePass; 107 } 108 /**//// 109 /// Return a string array containing the remote directory's file list. 110 /// 111 /// 112 /// 113 public string[] getFileList(string mask) 114 ...{ 115 if(!logined) 116 ...{ 117 login(); 118 } 119 Socket cSocket = createDataSocket(); 120 sendCommand("NLST " + mask); 121 if(!(retValue == 150 || retValue == 125)) 122 ...{ 123 throw new IOException(reply.Substring(4)); 124 } 125 mes = ""; 126 while(true) 127 ...{ 128 int bytes = cSocket.Receive(buffer, buffer.Length, 0); 129 mes += ASCII.GetString(buffer, 0, bytes); 130 if(bytes < buffer.Length) 131 ...{ 132 break; 133 } 134 } 135 char[] seperator = ...{' '}; 136 string[] mess = mes.Split(seperator); 137 cSocket.Close(); 138 readReply(); 139 if(retValue != 226) 140 ...{ 141 throw new IOException(reply.Substring(4)); 142 } 143 return mess; 144 } 145 /**//// 146 /// Return the size of a file. 147 /// 148 /// 149 /// 150 public long getFileSize(string fileName) 151 ...{ 152 if(!logined) 153 ...{ 154 login(); 155 } 156 sendCommand("SIZE " + fileName); 157 long size=0; 158 if(retValue == 213) 159 ...{ 160 size = Int64.Parse(reply.Substring(4)); 161 } 162 else 163 ...{ 164 throw new IOException(reply.Substring(4)); 165 } 166 return size; 167 } 168 /**//// 169 /// Login to the remote server. 170 /// 171 public void login() 172 ...{ 173 clientSocket = new 174 Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); 175 IPEndPoint ep = new 176 IPEndPoint(Dns.Resolve(remoteHost).AddressList[0], remotePort); 177 try 178 ...{ 179 clientSocket.Connect(ep); 180 } 181 catch(Exception) 182 ...{ 183 throw new IOException("Couldn't connect to remote server"); 184 } 185 readReply(); 186 if(retValue != 220) 187 ...{ 188 close(); 189 throw new IOException(reply.Substring(4)); 190 } 191 if(debug) 192 Console.WriteLine("USER "+remoteUser); 193 sendCommand("USER "+remoteUser); 194 if( !(retValue == 331 || retValue == 230) ) 195 ...{ 196 cleanup(); 197 throw new IOException(reply.Substring(4)); 198 } 199 if( retValue != 230 ) 200 ...{ 201 if(debug) 202 Console.WriteLine("PASS xxx"); 203 sendCommand("PASS "+remotePass); 204 if( !(retValue == 230 || retValue == 202) ) 205 ...{ 206 cleanup(); 207 throw new IOException(reply.Substring(4)); 208 } 209 } 210 logined = true; 211 Console.WriteLine("Connected to "+remoteHost); 212 chdir(remotePath); 213 } 214 /**//// 215 /// If the value of mode is true, set binary mode for downloads. 216 /// Else, set Ascii mode. 217 /// 218 /// 219 public void setBinaryMode(Boolean mode) 220 ...{ 221 if(mode) 222 ...{ 223 sendCommand("TYPE I"); 224 } 225 else 226 ...{ 227 sendCommand("TYPE A"); 228 } 229 if (retValue != 200) 230 ...{ 231 throw new IOException(reply.Substring(4)); 232 } 233 } 234 /**//// 235 /// Download a file to the Assembly's local directory, 236 /// keeping the same file name. 237 /// 238 /// 239 public void download(string remFileName) 240 ...{ 241 download(remFileName,"",false); 242 } 243 /**//// 244 /// Download a remote file to the Assembly's local directory, 245 /// keeping the same file name, and set the resume flag. 246 /// 247 /// 248 /// 249 public void download(string remFileName,Boolean resume) 250 ...{ 251 download(remFileName,"",resume); 252 } 253 /**//// 254 /// Download a remote file to a local file name which can include 255 /// a path. The local file name will be created or overwritten, 256 /// but the path must exist. 257 /// 258 /// 259 /// 260 public void download(string remFileName,string locFileName) 261 ...{ 262 download(remFileName,locFileName,false); 263 } 264 /**//// 265 /// Download a remote file to a local file name which can include 266 /// a path, and set the resume flag. The local file name will be 267 /// created or overwritten, but the path must exist. 268 /// 269 /// 270 /// 271 /// 272 public void download(string remFileName,string 273 locFileName,Boolean resume) 274 ...{ 275 if(!logined) 276 ...{ 277 login(); 278 } 279 setBinaryMode(true); 280 Console.WriteLine("Downloading file "+remFileName+" from "+remoteHost + "/"+remotePath); 281 if (locFileName.Equals("")) 282 ...{ 283 locFileName = remFileName; 284 } 285 if(!File.Exists(locFileName)) 286 ...{ 287 Stream st = File.Create(locFileName); 288 st.Close(); 289 } 290 FileStream output = new 291 FileStream(locFileName,FileMode.Open); 292 Socket cSocket = createDataSocket(); 293 long offset = 0; 294 if(resume) 295 ...{ 296 offset = output.Length; 297 if(offset > 0 ) 298 ...{ 299 sendCommand("REST "+offset); 300 if(retValue != 350) 301 ...{ 302 //throw new IOException(reply.Substring(4)); 303 //Some servers may not support resuming. 304 offset = 0; 305 } 306 } 307 if(offset > 0) 308 ...{ 309 if(debug) 310 ...{ 311 Console.WriteLine("seeking to " + offset); 312 } 313 long npos = output.Seek(offset,SeekOrigin.Begin); 314 Console.WriteLine("new pos="+npos); 315 } 316 } 317 sendCommand("RETR " + remFileName); 318 if(!(retValue == 150 || retValue == 125)) 319 ...{ 320 throw new IOException(reply.Substring(4)); 321 } 322 while(true) 323 ...{ 324 bytes = cSocket.Receive(buffer, buffer.Length, 0); 325 output.Write(buffer,0,bytes); 326 if(bytes <= 0) 327 ...{ 328 break; 329 } 330 } 331 output.Close(); 332 if (cSocket.Connected) 333 ...{ 334 cSocket.Close(); 335 } 336 Console.WriteLine(""); 337 readReply(); 338 if( !(retValue == 226 || retValue == 250) ) 339 ...{ 340 throw new IOException(reply.Substring(4)); 341 } 342 } 343 /**//// 344 /// Upload a file. 345 /// 346 /// 347 public void upload(string fileName) 348 ...{ 349 upload(fileName,false); 350 } 351 /**//// 352 /// Upload a file and set the resume flag. 353 /// 354 /// 355 /// 356 public void upload(string fileName,Boolean resume) 357 ...{ 358 if(!logined) 359 ...{ 360 login(); 361 } 362 Socket cSocket = createDataSocket(); 363 long offset=0; 364 if(resume) 365 ...{ 366 try 367 ...{ 368 setBinaryMode(true); 369 offset = getFileSize(fileName); 370 } 371 catch(Exception) 372 ...{ 373 offset = 0; 374 } 375 } 376 if(offset > 0 ) 377 ...{ 378 sendCommand("REST " + offset); 379 if(retValue != 350) 380 ...{ 381 //throw new IOException(reply.Substring(4)); 382 //Remote server may not support resuming. 383 offset = 0; 384 } 385 } 386 sendCommand("STOR "+Path.GetFileName(fileName)); 387 if( !(retValue == 125 || retValue == 150) ) 388 ...{ 389 throw new IOException(reply.Substring(4)); 390 } 391 // open input stream to read source file 392 FileStream input = new 393 FileStream(fileName,FileMode.Open); 394 if(offset != 0) 395 ...{ 396 if(debug) 397 ...{ 398 Console.WriteLine("seeking to " + offset); 399 } 400 input.Seek(offset,SeekOrigin.Begin); 401 } 402 Console.WriteLine("Uploading file "+fileName+" to "+remotePath); 403 while ((bytes = input.Read(buffer,0,buffer.Length)) > 0) 404 ...{ 405 cSocket.Send(buffer, bytes, 0); 406 } 407 input.Close(); 408 Console.WriteLine(""); 409 if (cSocket.Connected) 410 ...{ 411 cSocket.Close(); 412 } 413 readReply(); 414 if( !(retValue == 226 || retValue == 250) ) 415 ...{ 416 throw new IOException(reply.Substring(4)); 417 } 418 } 419 /**//// 420 /// Delete a file from the remote FTP server. 421 /// 422 /// 423 public void deleteRemoteFile(string fileName) 424 ...{ 425 if(!logined) 426 ...{ 427 login(); 428 } 429 sendCommand("DELE "+fileName); 430 if(retValue != 250) 431 ...{ 432 throw new IOException(reply.Substring(4)); 433 } 434 } 435 /**//// 436 /// Rename a file on the remote FTP server. 437 /// 438 /// 439 /// 440 public void renameRemoteFile(string oldFileName,string 441 newFileName) 442 ...{ 443 if(!logined) 444 ...{ 445 login(); 446 } 447 sendCommand("RNFR "+oldFileName); 448 if(retValue != 350) 449 ...{ 450 throw new IOException(reply.Substring(4)); 451 } 452 // known problem 453 // rnto will not take care of existing file. 454 // i.e. It will overwrite if newFileName exist 455 sendCommand("RNTO "+newFileName); 456 if(retValue != 250) 457 ...{ 458 throw new IOException(reply.Substring(4)); 459 } 460 } 461 /**//// 462 /// Create a directory on the remote FTP server. 463 /// 464 /// 465 public void mkdir(string dirName) 466 ...{ 467 if(!logined) 468 ...{ 469 login(); 470 } 471 sendCommand("MKD "+dirName); 472 if(retValue != 250) 473 ...{ 474 throw new IOException(reply.Substring(4)); 475 } 476 } 477 /**//// 478 /// Delete a directory on the remote FTP server. 479 /// 480 /// 481 public void rmdir(string dirName) 482 ...{ 483 if(!logined) 484 ...{ 485 login(); 486 } 487 sendCommand("RMD "+dirName); 488 if(retValue != 250) 489 ...{ 490 throw new IOException(reply.Substring(4)); 491 } 492 } 493 /**//// 494 /// Change the current working directory on the remote FTP server. 495 /// 496 /// 497 public void chdir(string dirName) 498 ...{ 499 if(dirName.Equals(".")) 500 ...{ 501 return; 502 } 503 if(!logined) 504 ...{ 505 login(); 506 } 507 sendCommand("CWD "+dirName); 508 if(retValue != 250) 509 ...{ 510 throw new IOException(reply.Substring(4)); 511 } 512 this.remotePath = dirName; 513 Console.WriteLine("Current directory is "+remotePath); 514 } 515 /**//// 516 /// Close the FTP connection. 517 /// 518 public void close() 519 ...{ 520 if( clientSocket != null ) 521 ...{ 522 sendCommand("QUIT"); 523 } 524 cleanup(); 525 Console.WriteLine("Closing..."); 526 } 527 /**//// 528 /// Set debug mode. 529 /// 530 /// 531 public void setDebug(Boolean debug) 532 ...{ 533 this.debug = debug; 534 } 535 private void readReply() 536 ...{ 537 mes = ""; 538 reply = readLine(); 539 retValue = Int32.Parse(reply.Substring(0,3)); 540 } 541 private void cleanup() 542 ...{ 543 if(clientSocket!=null) 544 ...{ 545 clientSocket.Close(); 546 clientSocket = null; 547 } 548 logined = false; 549 } 550 private string readLine() 551 ...{ 552 while(true) 553 ...{ 554 bytes = clientSocket.Receive(buffer, buffer.Length, 0); 555 mes += ASCII.GetString(buffer, 0, bytes); 556 if(bytes < buffer.Length) 557 ...{ 558 break; 559 } 560 } 561 char[] seperator = ...{' '}; 562 string[] mess = mes.Split(seperator); 563 if(mes.Length > 2) 564 ...{ 565 mes = mess[mess.Length-2]; 566 } 567 else 568 ...{ 569 mes = mess[0]; 570 } 571 if(!mes.Substring(3,1).Equals(" ")) 572 ...{ 573 return readLine(); 574 } 575 if(debug) 576 ...{ 577 for(int k=0;k < mess.Length-1;k++) 578 ...{ 579 Console.WriteLine(mess[k]); 580 } 581 } 582 return mes; 583 } 584 private void sendCommand(String command) 585 ...{ 586 Byte[] cmdBytes = 587 Encoding.ASCII.GetBytes((command+" ").ToCharArray()); 588 clientSocket.Send(cmdBytes, cmdBytes.Length, 0); 589 readReply(); 590 } 591 private Socket createDataSocket() 592 ...{ 593 sendCommand("PASV"); 594 if(retValue != 227) 595 ...{ 596 throw new IOException(reply.Substring(4)); 597 } 598 int index1 = reply.IndexOf('('); 599 int index2 = reply.IndexOf(')'); 600 string ipData = 601 reply.Substring(index1+1,index2-index1-1); 602 int[] parts = new int[6]; 603 int len = ipData.Length; 604 int partCount = 0; 605 string buf=""; 606 for (int i = 0; i < len && partCount <= 6; i++) 607 ...{ 608 char ch = Char.Parse(ipData.Substring(i,1)); 609 if (Char.IsDigit(ch)) 610 buf+=ch; 611 else if (ch != ',') 612 ...{ 613 throw new IOException("Malformed PASV reply: " + 614 reply); 615 } 616 if (ch == ',' || i+1 == len) 617 ...{ 618 try 619 ...{ 620 parts[partCount++] = Int32.Parse(buf); 621 buf=""; 622 } 623 catch (Exception) 624 ...{ 625 throw new IOException("Malformed PASV reply: " + 626 reply); 627 } 628 } 629 } 630 string ipAddress = parts[0] + "."+ parts[1]+ "." + 631 parts[2] + "." + parts[3]; 632 int port = (parts[4] << 8) + parts[5]; 633 Socket s = new 634 Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); 635 IPEndPoint ep = new 636 IPEndPoint(Dns.Resolve(ipAddress).AddressList[0], port); 637 try 638 ...{ 639 s.Connect(ep); 640 } 641 catch(Exception) 642 ...{ 643 throw new IOException("Can't connect to remote server"); 644 } 645 return s; 646 } 647 } 648 }
以上是在C#项目下添加ftp类
配置ftp 服务器 (xp下局域网内)
1.server下,打开设置-->控制面板-->管理工具-->IIS,找到本地计算机下的ftp站点,打开默认ftp站点的属性,做如下配置:
1)ftp站点选项卡
IP地址:指定一IP地址,如:192.168.0.101
端口号:21
2)主目录选项卡
选择内容来源为:此计算机上的目录
ftp站点目录:配置一本机目录,最好为非系统盘,如D:/ftp。选择读取、写入、记录访问
2.server下,网络邻居里的本地连接,属性-->常规-->TCP/IP协议-->属性,取消自动获取IP地址,手动输入如上IP:192.168.0.101
3.client下,网络邻居里的本地连接,属性-->常规-->TCP/IP协议-->属性,取消自动获取IP地址,手动输入IP:192.168.0.102
4:测试:把文件copy到ftp主目录下,即D:/ftp,通过在server端以及client端的IE,输入ftp://192.168.0.101或者ftp://servername (作为服务器的计算机名,可在我的电脑-->属性-->计算机名里获得)可访问到文件,则测试成功。
在主函数中创建实例
查看代码
说明:
1.参数设置
1)RemoteHost=server的IP地址
2)RemoteUser=用户名,匿名情况下不能为" ",而应为"Anonymous"
3)此处的chdir或别处的remotePath,为设置或修改服务器的当前目录,若没有当前目录(只有根目录),应设置为"."。比较奇怪的是我试过“D:/ftp/”(服务器主目录以及其变形“/ftp”等)或者ftp://servername/(或者“//servername/”等),都无法识别,盼高人指点
4) ftp应答码及其意义
110
重新启动标记应答。在这种情况下文本是确定的,它必须是:MARK yyyy=mmmm,其中yyyy是用户进程数据流标记,mmmm是服务器标记。
120
服务在nnn分钟内準备好
125
数据连接已打开,準备传送
150
文件状态良好,打开数据连接
200
命令成功
202
命令未实现
211
系统状态或系统帮助响应
212
目录状态
213
文件状态
214
帮助信息,信息仅对人类用户有用
215
名字系统类型
220
对新用户服务準备好
221
服务关闭控制连接,可以退出登录
225
数据连接打开,无传输正在进行
226
关闭数据连接,请求的文件操作成功
227
进入被动模式
230
用户登录
250
请求的文件操作完成
257
创建"PATHNAME"
331
用户名正确,需要口令
332
登录时需要帐户信息
350
请求的文件操作需要进一步命令
421
不能提供服务,关闭控制连接
425
不能打开数据连接
426
关闭连接,中止传输
450
请求的文件操作未执行
451
中止请求的操作:有本地错误
452
未执行请求的操作:系统存储空间不足
500
格式错误,命令不可识别
501
参数语法错误
502
命令未实现
503
命令顺序错误
504
此参数下的命令功能未实现
530
未登录
532
存储文件需要帐户信息
550
未执行请求的操作
551
请求操作中止:页类型未知
552
请求的文件操作中止,存储分配溢出
553
未执行请求的操作:文件名不合法