Ftp协议Socket实现
原来用WebRequest来传输文件,被人鄙视了。就弄个Socket版的,支持Active,Passive模式。
带事件日志,有时间的人可以拿去做C#版的flashfxp。
1 public class FtpClient 2 { 3 public class FtpLogEventArgs : EventArgs 4 { 5 private string mStrLog = string.Empty; 6 public string Log 7 { 8 get 9 { 10 return this.mStrLog; 11 } 12 } 13 public FtpLogEventArgs(string strLog) 14 { 15 this.mStrLog = strLog; 16 } 17 } 18 public delegate void FtpLogEventHandler(object sender, FtpLogEventArgs e); 19 public class FtpTranProgressEventArgs : EventArgs 20 { 21 private uint mPercent = 0u; 22 private bool mCancel = false; 23 public uint Percent 24 { 25 get 26 { 27 return this.mPercent; 28 } 29 } 30 public bool Cancel 31 { 32 get 33 { 34 return this.mCancel; 35 } 36 set 37 { 38 } 39 } 40 public FtpTranProgressEventArgs(uint percent) 41 { 42 this.mPercent = percent; 43 this.mCancel = false; 44 } 45 } 46 public delegate void FtpTranProgressEventHandler(object sender, FtpTranProgressEventArgs e); 47 public enum FtpTransferType 48 { 49 Binary, 50 ASCII 51 } 52 public enum FtpMode 53 { 54 Active, 55 Passive 56 } 57 public enum FtpSystemType 58 { 59 UNIX, 60 WINDOWS 61 } 62 private Socket mSocketConnect = null; 63 private string mStrServer = string.Empty; 64 private int mIntPort = 21; 65 private string mStrUser = string.Empty; 66 private string mStrPassword = string.Empty; 67 private string mStrPath = string.Empty; 68 private bool mIsConnected = false; 69 private FtpMode mMode = FtpMode.Passive; 70 private FtpSystemType mSystemType = FtpSystemType.UNIX; 71 private string mStrReply = string.Empty; 72 private int mIntReplyCode = 0; 73 private static int BLOCK_SIZE = 2048; 74 private byte[] mBuffer = new byte[FtpClient.BLOCK_SIZE]; 75 76 private event FtpLogEventHandler mFtpLogEvent; 77 public event FtpLogEventHandler FtpLogEvent 78 { 79 add 80 { 81 FtpLogEventHandler handlerTemp; 82 FtpLogEventHandler fieldsChanged = this.mFtpLogEvent; 83 do 84 { 85 handlerTemp = fieldsChanged; 86 FtpLogEventHandler handlerRes = (FtpLogEventHandler)Delegate.Combine(handlerTemp, value); 87 fieldsChanged = Interlocked.CompareExchange<FtpLogEventHandler>(ref this.mFtpLogEvent, handlerRes, handlerTemp); 88 } 89 while (fieldsChanged != handlerTemp); 90 } 91 92 remove 93 { 94 FtpLogEventHandler handlerTemp; 95 FtpLogEventHandler fieldsChanged = this.mFtpLogEvent; 96 do 97 { 98 handlerTemp = fieldsChanged; 99 FtpLogEventHandler handlerRes = (FtpLogEventHandler)Delegate.Remove(handlerTemp, value); 100 fieldsChanged = Interlocked.CompareExchange<FtpLogEventHandler>(ref this.mFtpLogEvent, handlerRes, handlerTemp); 101 } 102 while (fieldsChanged != handlerTemp); 103 } 104 } 105 106 private event FtpTranProgressEventHandler mFtpTranProgressEvent; 107 public event FtpTranProgressEventHandler FtpTranProgressEvent 108 { 109 add 110 { 111 FtpTranProgressEventHandler handlerTemp; 112 FtpTranProgressEventHandler fieldsChanged = this.mFtpTranProgressEvent; 113 do 114 { 115 handlerTemp = fieldsChanged; 116 FtpTranProgressEventHandler handlerRes = (FtpTranProgressEventHandler)Delegate.Combine(handlerTemp, value); 117 fieldsChanged = Interlocked.CompareExchange<FtpTranProgressEventHandler>(ref this.mFtpTranProgressEvent, handlerRes, handlerTemp); 118 } 119 while (fieldsChanged != handlerTemp); 120 } 121 remove 122 { 123 FtpTranProgressEventHandler handlerTemp; 124 FtpTranProgressEventHandler fieldsChanged = this.mFtpTranProgressEvent; 125 do 126 { 127 handlerTemp = fieldsChanged; 128 FtpTranProgressEventHandler handlerRes = (FtpTranProgressEventHandler)Delegate.Remove(handlerTemp, value); 129 fieldsChanged = Interlocked.CompareExchange<FtpTranProgressEventHandler>(ref this.mFtpTranProgressEvent, handlerRes, handlerTemp); 130 } 131 while (fieldsChanged != handlerTemp); 132 } 133 } 134 public bool Connected 135 { 136 get 137 { 138 return this.mIsConnected; 139 } 140 } 141 public FtpTransferType TransferType 142 { 143 set 144 { 145 if (value == FtpTransferType.Binary) 146 { 147 this.SendCommand("TYPE I"); 148 } 149 else 150 { 151 this.SendCommand("TYPE A"); 152 } 153 if (this.mIntReplyCode != 200) 154 { 155 throw new IOException(this.mStrReply.Substring(4)); 156 } 157 } 158 } 159 public FtpMode Mode 160 { 161 get 162 { 163 return this.mMode; 164 } 165 set 166 { 167 this.mMode = value; 168 } 169 } 170 public FtpSystemType SystemType 171 { 172 get 173 { 174 return this.mSystemType; 175 } 176 set 177 { 178 this.mSystemType = value; 179 } 180 } 181 protected virtual void OnFtpLogEvent(FtpLogEventArgs e) 182 { 183 if (this.mFtpLogEvent != null) 184 { 185 this.mFtpLogEvent(this, e); 186 } 187 } 188 protected virtual void OnFtpTranProgressEvent(FtpTranProgressEventArgs e) 189 { 190 if (this.mFtpTranProgressEvent != null) 191 { 192 this.mFtpTranProgressEvent(this, e); 193 } 194 } 195 public FtpClient(string server, string path, string user, string password, int port, FtpClient.FtpMode mode) 196 { 197 this.mStrServer = server; 198 this.mStrPath = path; 199 this.mStrUser = user; 200 this.mStrPassword = password; 201 this.mIntPort = port; 202 this.mMode = mode; 203 } 204 public void Connect() 205 { 206 this.mSocketConnect = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 207 IPHostEntry ipHost = Dns.GetHostEntry(this.mStrServer); 208 IPEndPoint iPEndPoint = new IPEndPoint(ipHost.AddressList[0], this.mIntPort); 209 try 210 { 211 this.mSocketConnect.Connect(iPEndPoint); 212 } 213 catch (Exception) 214 { 215 throw new IOException("Couldn't connect to remote server"); 216 } 217 this.ReadReply(); 218 if (this.mIntReplyCode != 220) 219 { 220 this.DisConnect(); 221 throw new IOException(this.mStrReply.Substring(4)); 222 } 223 this.SendCommand("USER " + this.mStrUser); 224 if (this.mIntReplyCode != 331 && this.mIntReplyCode != 230) 225 { 226 this.CloseSocketConnect(); 227 throw new IOException(this.mStrReply.Substring(4)); 228 } 229 if (this.mIntReplyCode == 331) 230 { 231 this.SendCommand("PASS " + this.mStrPassword); 232 if (this.mIntReplyCode != 230 && this.mIntReplyCode != 202) 233 { 234 this.CloseSocketConnect(); 235 throw new IOException(this.mStrReply.Substring(4)); 236 } 237 } 238 this.SendCommand("SYST"); 239 if (this.mIntReplyCode != 215) 240 { 241 this.CloseSocketConnect(); 242 throw new IOException(this.mStrReply.Substring(4)); 243 } 244 245 if (this.mStrReply[4].ToString() == "W" || this.mStrReply[4].ToString() == "w") 246 { 247 this.mSystemType = FtpClient.FtpSystemType.WINDOWS; 248 } 249 this.mIsConnected = true; 250 this.ChDir(this.mStrPath); 251 } 252 public void DisConnect() 253 { 254 this.CloseSocketConnect(); 255 } 256 public void ChDir(string strDirName) 257 { 258 if (strDirName.Equals("")) 259 { 260 return; 261 } 262 if (!this.mIsConnected) 263 { 264 this.Connect(); 265 } 266 this.SendCommand("CWD " + strDirName); 267 if (this.mIntReplyCode != 250) 268 { 269 throw new IOException(this.mStrReply.Substring(4)); 270 } 271 this.mStrPath = strDirName; 272 } 273 public void Reset(long size) 274 { 275 if (!this.mIsConnected) 276 { 277 this.Connect(); 278 } 279 this.SendCommand("REST " + size.ToString()); 280 if (this.mIntReplyCode != 350) 281 { 282 throw new IOException(this.mStrReply.Substring(4)); 283 } 284 } 285 public string[] Dir(string strMark) 286 { 287 if (!this.mIsConnected) 288 { 289 this.Connect(); 290 } 291 char[] array = new char[] 292 { 293 '\n' 294 }; 295 string text; 296 string[] result; 297 if (this.mMode == FtpClient.FtpMode.Active) 298 { 299 TcpListener tcpListener = null; 300 this.CreateDataListener(ref tcpListener); 301 this.TransferType = FtpClient.FtpTransferType.ASCII; 302 this.SendCommand("LIST"); 303 Socket socket = tcpListener.AcceptSocket(); 304 text = ""; 305 int num; 306 do 307 { 308 num = socket.Receive(this.mBuffer, this.mBuffer.Length, 0); 309 text += Encoding.Default.GetString(this.mBuffer, 0, num); 310 } 311 while (num >= this.mBuffer.Length); 312 result = text.Split(array); 313 socket.Close(); 314 tcpListener.Stop(); 315 return result; 316 } 317 Socket socket2 = this.CreateDataSocket(); 318 this.SendCommand("LIST"); 319 if (this.mIntReplyCode != 150 && this.mIntReplyCode != 125 && this.mIntReplyCode != 226) 320 { 321 throw new IOException(this.mStrReply.Substring(4)); 322 } 323 text = ""; 324 int num2; 325 do 326 { 327 num2 = socket2.Receive(this.mBuffer, this.mBuffer.Length, 0); 328 text += Encoding.Default.GetString(this.mBuffer, 0, num2); 329 } 330 while (num2 >= this.mBuffer.Length); 331 result = text.Split(array); 332 socket2.Close(); 333 if (this.mIntReplyCode != 226) 334 { 335 this.ReadReply(); 336 if (this.mIntReplyCode != 226) 337 { 338 throw new IOException(this.mStrReply.Substring(4)); 339 } 340 } 341 return result; 342 } 343 public void UploadFile(string strFile) 344 { 345 if (!this.mIsConnected) 346 { 347 this.Connect(); 348 } 349 if (this.mMode == FtpClient.FtpMode.Active) 350 { 351 TcpListener tcpListener = null; 352 this.CreateDataListener(ref tcpListener); 353 this.TransferType = FtpClient.FtpTransferType.Binary; 354 this.SendCommand("STOR " + Path.GetFileName(strFile)); 355 if (this.mIntReplyCode != 125 && this.mIntReplyCode != 150) 356 { 357 throw new IOException(this.mStrReply.Substring(4)); 358 } 359 Socket socket = tcpListener.AcceptSocket(); 360 FileStream fileStream = new FileStream(strFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 361 long length = fileStream.Length; 362 long num = 0L; 363 int num2; 364 while ((num2 = fileStream.Read(this.mBuffer, 0, this.mBuffer.Length)) > 0) 365 { 366 num += (long)num2; 367 uint percent = (uint)(num * 100L / length); 368 FtpClient.FtpTranProgressEventArgs e = new FtpClient.FtpTranProgressEventArgs(percent); 369 this.OnFtpTranProgressEvent(e); 370 socket.Send(this.mBuffer, num2, 0); 371 } 372 fileStream.Close(); 373 if (socket.Connected) 374 { 375 socket.Close(); 376 } 377 tcpListener.Stop(); 378 return; 379 } 380 else 381 { 382 Socket socket2 = this.CreateDataSocket(); 383 this.SendCommand("STOR " + Path.GetFileName(strFile)); 384 if (this.mIntReplyCode != 125 && this.mIntReplyCode != 150) 385 { 386 throw new IOException(this.mStrReply.Substring(4)); 387 } 388 FileStream fileStream2 = new FileStream(strFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 389 long length = fileStream2.Length; 390 long num = 0L; 391 int num2; 392 while ((num2 = fileStream2.Read(this.mBuffer, 0, this.mBuffer.Length)) > 0) 393 { 394 num += (long)num2; 395 uint percent = (uint)(num * 100L / length); 396 FtpClient.FtpTranProgressEventArgs e2 = new FtpClient.FtpTranProgressEventArgs(percent); 397 this.OnFtpTranProgressEvent(e2); 398 socket2.Send(this.mBuffer, num2, 0); 399 } 400 fileStream2.Close(); 401 if (socket2.Connected) 402 { 403 socket2.Close(); 404 } 405 if (this.mIntReplyCode != 226 && this.mIntReplyCode != 250) 406 { 407 this.ReadReply(); 408 if (this.mIntReplyCode != 226 && this.mIntReplyCode != 250) 409 { 410 throw new IOException(this.mStrReply.Substring(4)); 411 } 412 } 413 return; 414 } 415 } 416 public void DownloadFile(string strRemoteFileName, string strLocalFolder, string strLocalFileName) 417 { 418 if (!this.mIsConnected) 419 { 420 this.Connect(); 421 } 422 if (this.mMode == FtpClient.FtpMode.Active) 423 { 424 TcpListener tcpListener = null; 425 this.CreateDataListener(ref tcpListener); 426 string extension = Path.GetExtension(strRemoteFileName); 427 if (extension != ".txt" && extension != ".TXT") 428 { 429 this.TransferType = FtpClient.FtpTransferType.Binary; 430 } 431 if (strLocalFileName == "") 432 { 433 strLocalFileName = strRemoteFileName; 434 } 435 FileStream fileStream = new FileStream(strLocalFolder + "\\" + strLocalFileName, FileMode.Create); 436 this.SendCommand("RETR " + strRemoteFileName); 437 if (this.mIntReplyCode != 150 && this.mIntReplyCode != 125 && this.mIntReplyCode != 226 && this.mIntReplyCode != 250 && this.mIntReplyCode != 200) 438 { 439 fileStream.Close(); 440 throw new IOException(this.mStrReply.Substring(4)); 441 } 442 Socket socket = tcpListener.AcceptSocket(); 443 while (true) 444 { 445 int num = socket.Receive(this.mBuffer, this.mBuffer.Length, 0); 446 if (num <= 0) 447 { 448 break; 449 } 450 fileStream.Write(this.mBuffer, 0, num); 451 } 452 fileStream.Close(); 453 if (socket.Connected) 454 { 455 socket.Close(); 456 } 457 if (this.mIntReplyCode != 226 && this.mIntReplyCode != 250) 458 { 459 this.ReadReply(); 460 if (this.mIntReplyCode != 226 && this.mIntReplyCode != 250) 461 { 462 throw new IOException(this.mStrReply.Substring(4)); 463 } 464 } 465 tcpListener.Stop(); 466 return; 467 } 468 else 469 { 470 string extension2 = Path.GetExtension(strRemoteFileName); 471 if (extension2 != ".txt" && extension2 != ".TXT") 472 { 473 this.TransferType = FtpClient.FtpTransferType.Binary; 474 } 475 if (strLocalFileName == "") 476 { 477 strLocalFileName = strRemoteFileName; 478 } 479 FileStream fileStream2 = new FileStream(strLocalFolder + "\\" + strLocalFileName, FileMode.Create); 480 Socket socket2 = this.CreateDataSocket(); 481 this.SendCommand("RETR " + strRemoteFileName); 482 if (this.mIntReplyCode != 150 && this.mIntReplyCode != 125 && this.mIntReplyCode != 226 && this.mIntReplyCode != 250) 483 { 484 fileStream2.Close(); 485 throw new IOException(this.mStrReply.Substring(4)); 486 } 487 while (true) 488 { 489 int num2 = socket2.Receive(this.mBuffer, this.mBuffer.Length, 0); 490 if (num2 <= 0) 491 { 492 break; 493 } 494 fileStream2.Write(this.mBuffer, 0, num2); 495 } 496 fileStream2.Close(); 497 if (socket2.Connected) 498 { 499 socket2.Close(); 500 } 501 if (this.mIntReplyCode != 226 && this.mIntReplyCode != 250) 502 { 503 this.ReadReply(); 504 if (this.mIntReplyCode != 226 && this.mIntReplyCode != 250) 505 { 506 throw new IOException(this.mStrReply.Substring(4)); 507 } 508 } 509 return; 510 } 511 } 512 513 public void CreateDir(string strDirName) 514 { 515 if (!this.mIsConnected) 516 { 517 this.Connect(); 518 } 519 this.SendCommand("MKD " + strDirName); 520 if (this.mIntReplyCode != 257) 521 { 522 throw new IOException(this.mStrReply.Substring(4)); 523 } 524 } 525 526 public void DeleteDir(string strDirName) 527 { 528 if (!this.mIsConnected) 529 { 530 this.Connect(); 531 } 532 this.SendCommand("RMD " + strDirName); 533 if (this.mIntReplyCode != 250) 534 { 535 throw new IOException(this.mStrReply.Substring(4)); 536 } 537 } 538 539 public void DeleteFile(string strFile) 540 { 541 if (!this.mIsConnected) 542 { 543 this.Connect(); 544 } 545 this.SendCommand("DELE " + strFile); 546 if (this.mIntReplyCode != 250) 547 { 548 throw new IOException(this.mStrReply.Substring(4)); 549 } 550 } 551 private long GetFileSize(string strFileName) 552 { 553 if (!this.mIsConnected) 554 { 555 this.Connect(); 556 } 557 this.SendCommand("SIZE " + Path.GetFileName(strFileName)); 558 if (this.mIntReplyCode == 213 || this.mIntReplyCode == 200) 559 { 560 return long.Parse(this.mStrReply.Substring(4)); 561 } 562 throw new IOException(this.mStrReply.Substring(4)); 563 } 564 private string ReadLine() 565 { 566 string text = string.Empty; 567 Thread.Sleep(200); 568 int num; 569 do 570 { 571 text = ""; 572 num = this.mSocketConnect.Receive(this.mBuffer, this.mBuffer.Length, 0); 573 text += Encoding.Default.GetString(this.mBuffer, 0, num); 574 FtpLogEventArgs e = new FtpLogEventArgs("应答: " + text); 575 this.OnFtpLogEvent(e); 576 } 577 while (num >= this.mBuffer.Length); 578 char[] array = new char[] 579 { 580 '\n' 581 }; 582 string[] array2 = text.Split(array); 583 if (text.Length > 2) 584 { 585 text = array2[array2.Length - 2]; 586 } 587 else 588 { 589 text = array2[0]; 590 } 591 if (!text.Substring(3, 1).Equals(" ")) 592 { 593 return this.ReadLine(); 594 } 595 return text; 596 } 597 private void ReadReply() 598 { 599 this.mStrReply = this.ReadLine(); 600 this.mIntReplyCode = int.Parse(this.mStrReply.Substring(0, 3)); 601 } 602 private void SendCommand(string strCommand) 603 { 604 FtpLogEventArgs e = new FtpLogEventArgs("命令: " + strCommand); 605 this.OnFtpLogEvent(e); 606 byte[] bytes = Encoding.Default.GetBytes((strCommand + "\r\n").ToCharArray()); 607 this.mSocketConnect.Send(bytes, bytes.Length, 0); 608 this.ReadReply(); 609 } 610 private void CloseSocketConnect() 611 { 612 if (this.mSocketConnect != null) 613 { 614 this.mSocketConnect.Close(); 615 this.mSocketConnect = null; 616 } 617 this.mIsConnected = false; 618 } 619 private Socket CreateDataSocket() 620 { 621 Socket result; 622 try 623 { 624 this.SendCommand("PASV"); 625 if (this.mIntReplyCode != 227) 626 { 627 throw new IOException(this.mStrReply.Substring(4)); 628 } 629 int num = this.mStrReply.IndexOf('('); 630 int num2 = this.mStrReply.IndexOf(')'); 631 string text = this.mStrReply.Substring(num + 1, num2 - num - 1); 632 string[] array = new string[6]; 633 array = text.Split(new char[] 634 { 635 ',' 636 }); 637 if (array.Length != 6) 638 { 639 throw new IOException("Malformed PASV strReply: " + this.mStrReply); 640 } 641 string text2 = string.Concat(new string[] 642 { 643 array[0], 644 ".", 645 array[1], 646 ".", 647 array[2], 648 ".", 649 array[3] 650 }); 651 try 652 { 653 num = int.Parse(array[4]); 654 num2 = int.Parse(array[5]); 655 } 656 catch 657 { 658 throw new IOException("Malformed PASV strReply: " + this.mStrReply); 659 } 660 int num3 = (num << 8) + num2; 661 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 662 IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(text2), num3); 663 try 664 { 665 socket.Connect(iPEndPoint); 666 } 667 catch (Exception) 668 { 669 throw new IOException("Can't connect to remote server"); 670 } 671 result = socket; 672 } 673 catch (Exception ex) 674 { 675 throw new Exception(ex.ToString()); 676 } 677 return result; 678 } 679 private void CreateDataListener(ref TcpListener listener) 680 { 681 string hostName = Dns.GetHostName(); 682 IPAddress iPAddress = Dns.GetHostEntry(hostName).AddressList[0]; 683 listener = new TcpListener(iPAddress, 0); 684 listener.Start(); 685 IPEndPoint iPEndPoint = (IPEndPoint)listener.LocalEndpoint; 686 int num = iPEndPoint.Port >> 8; 687 int num2 = iPEndPoint.Port & 255; 688 this.SendCommand(string.Concat(new string[] 689 { 690 "PORT ", 691 iPEndPoint.Address.ToString().Replace(".", ","), 692 ",", 693 num.ToString(), 694 ",", 695 num2.ToString() 696 })); 697 if (this.mIntReplyCode != 200 && this.mIntReplyCode != 226) 698 { 699 throw new IOException(this.mStrReply.Substring(4)); 700 } 701 } 702 }
简单使用
1 FtpClient ftpClient = new FtpClient(ip, "/", user, pass, 21, FtpClient.FtpMode.Passive); 2 ftpClient.FtpTranProgressEvent += (s, e) => 3 { 4 progress.Value = (int)e.Percent; 5 Application.DoEvents(); 6 }; 7 8 try 9 { 10 ftpClient.Connect(); 11 } 12 catch (Exception ex) 13 { 14 ftpClient = null; 15 return; 16 } 17 18 if (ftpClient.Connected) 19 { 20 ftpClient.CreateDir(root); 21 ftpClient.ChDir(root); 22 23 try 24 { 25 ftpClient.UploadFile(@"D:\shin_angyo_onshi\Vol_SP\001.jpg"); 26 } 27 catch (Exception ex) 28 { 29 MessageBox.Show(ex.Message.ToString()); 30 return; 31 } 32 }
作者:Kurodo
出处:http://Kurodo.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://Kurodo.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。