首页 新闻 搜索 专区 学院

socket 多线程ftp 无限等待的问题.有代码

0
悬赏园豆:50 [已关闭问题] 关闭于 2011-03-07 18:35

先上ftp的代码,代码如下,这个是从Discuz.net版本里找的

 

FTP代码
1 using System;
2  using System.Collections.Generic;
3  using System.Linq;
4  using System.Text;
5  using System.Net.Sockets;
6  using System.Net;
7 using System.IO;
8 using System.Collections;
9 using System.Text.RegularExpressions;
10
11 namespace Common
12 {
13 public class Ftp_Socket
14 {
15 #region 变量声明
16
17 /// <summary>
18 /// 服务器连接地址
19 /// </summary>
20 public string server;
21
22 /// <summary>
23 /// 登陆帐号
24 /// </summary>
25 public string user;
26
27 /// <summary>
28 /// 登陆口令
29 /// </summary>
30 public string pass;
31
32 /// <summary>
33 /// 端口号
34 /// </summary>
35 public int port;
36
37 /// <summary>
38 /// 无响应时间(FTP在指定时间内无响应)
39 /// </summary>
40 public int timeout;
41
42 /// <summary>
43 /// 服务器错误状态信息
44 /// </summary>
45 public string errormessage;
46
47
48 /// <summary>
49 /// 服务器状态返回信息
50 /// </summary>
51 private string messages;
52
53 /// <summary>
54 /// 服务器的响应信息
55 /// </summary>
56 private string responseStr;
57
58 /// <summary>
59 /// 链接模式(主动或被动,默认为被动)
60 /// </summary>
61 private bool passive_mode;
62
63 /// <summary>
64 /// 上传或下载信息字节数
65 /// </summary>
66 private long bytes_total;
67
68 /// <summary>
69 /// 上传或下载的文件大小
70 /// </summary>
71 private long file_size;
72
73 /// <summary>
74 /// 主套接字
75 /// </summary>
76 private Socket main_sock;
77
78 /// <summary>
79 /// 要链接的网络地址终结点
80 /// </summary>
81 private IPEndPoint main_ipEndPoint;
82
83 /// <summary>
84 /// 侦听套接字
85 /// </summary>
86 private Socket listening_sock;
87
88 /// <summary>
89 /// 数据套接字
90 /// </summary>
91 private Socket data_sock;
92
93 /// <summary>
94 /// 要链接的网络数据地址终结点
95 /// </summary>
96 private IPEndPoint data_ipEndPoint;
97
98 /// <summary>
99 /// 用于上传或下载的文件流对象
100 /// </summary>
101 private FileStream file;
102
103 /// <summary>
104 /// 与FTP服务器交互的状态值
105 /// </summary>
106 private int response;
107
108 /// <summary>
109 /// 读取并保存当前命令执行后从FTP服务器端返回的数据信息
110 /// </summary>
111 private string bucket;
112
113 string webConfigPassiveMode = "false";
114
115 #endregion
116
117 #region 构造函数
118
119 /// <summary>
120 /// 构造函数
121 /// </summary>
122 public Ftp_Socket()
123 {
124 server = null;
125 user = null;
126 pass = null;
127 port = 21;
128 passive_mode = (webConfigPassiveMode == "true" ? true : false);
129 main_sock = null;
130 main_ipEndPoint = null;
131 listening_sock = null;
132 data_sock = null;
133 data_ipEndPoint = null;
134 file = null;
135 bucket = "";
136 bytes_total = 0;
137 timeout = 10000; //无响应时间为10秒
138 messages = "";
139 errormessage = "";
140 }
141
142 /// <summary>
143 /// 构造函数
144 /// </summary>
145 /// <param name="server">服务器IP或名称</param>
146 /// <param name="user">登陆帐号</param>
147 /// <param name="pass">登陆口令</param>
148 public Ftp_Socket(string server, string user, string pass)
149 {
150 this.server = server;
151 this.user = user;
152 this.pass = pass;
153 port = 21;
154 passive_mode = (webConfigPassiveMode == "true" ? true : false);
155 main_sock = null;
156 main_ipEndPoint = null;
157 listening_sock = null;
158 data_sock = null;
159 data_ipEndPoint = null;
160 file = null;
161 bucket = "";
162 bytes_total = 0;
163 timeout = 10000; //无响应时间为10秒
164 messages = "";
165 errormessage = "";
166 }
167
168 /// <summary>
169 /// 构造函数
170 /// </summary>
171 /// <param name="server">服务器IP或名称</param>
172 /// <param name="port">端口号</param>
173 /// <param name="user">登陆帐号</param>
174 /// <param name="pass">登陆口令</param>
175 public Ftp_Socket(string server, int port, string user, string pass)
176 {
177 this.server = server;
178 this.user = user;
179 this.pass = pass;
180 this.port = port;
181 passive_mode = (webConfigPassiveMode == "true" ? true : false);
182 main_sock = null;
183 main_ipEndPoint = null;
184 listening_sock = null;
185 data_sock = null;
186 data_ipEndPoint = null;
187 file = null;
188 bucket = "";
189 bytes_total = 0;
190 timeout = 10000; //无响应时间为10秒
191 messages = "";
192 errormessage = "";
193 }
194
195
196 /// <summary>
197 /// 构造函数
198 /// </summary>
199 /// <param name="server">服务器IP或名称</param>
200 /// <param name="port">端口号</param>
201 /// <param name="user">登陆帐号</param>
202 /// <param name="pass">登陆口令</param>
203 /// <param name="mode">链接方式</param>
204 public Ftp_Socket(string server, int port, string user, string pass, int mode)
205 {
206 this.server = server;
207 this.user = user;
208 this.pass = pass;
209 this.port = port;
210 passive_mode = mode <= 1 ? true : false;
211 main_sock = null;
212 main_ipEndPoint = null;
213 listening_sock = null;
214 data_sock = null;
215 data_ipEndPoint = null;
216 file = null;
217 bucket = "";
218 bytes_total = 0;
219 this.timeout = 10000; //无响应时间为10秒
220 messages = "";
221 errormessage = "";
222 }
223
224 /// <summary>
225 /// 构造函数
226 /// </summary>
227 /// <param name="server">服务器IP或名称</param>
228 /// <param name="port">端口号</param>
229 /// <param name="user">登陆帐号</param>
230 /// <param name="pass">登陆口令</param>
231 /// <param name="mode">链接方式</param>
232 /// <param name="timeout">无响应时间(限时),单位:秒 (小于或等于0为不受时间限制)</param>
233 public Ftp_Socket(string server, int port, string user, string pass, int mode, int timeout_sec)
234 {
235 this.server = server;
236 this.user = user;
237 this.pass = pass;
238 this.port = port;
239 passive_mode = mode <= 1 ? true : false;
240 main_sock = null;
241 main_ipEndPoint = null;
242 listening_sock = null;
243 data_sock = null;
244 data_ipEndPoint = null;
245 file = null;
246 bucket = "";
247 bytes_total = 0;
248 this.timeout = (timeout_sec <= 0) ? int.MaxValue : (timeout_sec * 1000); //无响应时间
249 messages = "";
250 errormessage = "";
251 }
252
253 #endregion
254
255 #region 属性
256 /// <summary>
257 /// 当前是否已连接
258 /// </summary>
259 public bool IsConnected
260 {
261 get
262 {
263 if (main_sock != null)
264 return main_sock.Connected;
265 return false;
266 }
267 }
268
269 /// <summary>
270 /// 当message缓冲区有数据则返回
271 /// </summary>
272 public bool MessagesAvailable
273 {
274 get
275 {
276 if (messages.Length > 0)
277 return true;
278 return false;
279 }
280 }
281
282 /// <summary>
283 /// 获取服务器状态返回信息, 并清空messages变量
284 /// </summary>
285 public string Messages
286 {
287 get
288 {
289 string tmp = messages;
290 messages = "";
291 return tmp;
292 }
293 }
294 /// <summary>
295 /// 最新指令发出后服务器的响应
296 /// </summary>
297 public string ResponseString
298 {
299 get
300 {
301 return responseStr;
302 }
303 }
304
305
306 /// <summary>
307 ///在一次传输中,发送或接收的字节数
308 /// </summary>
309 public long BytesTotal
310 {
311 get
312 {
313 return bytes_total;
314 }
315 }
316
317 /// <summary>
318 ///被下载或上传的文件大小,当文件大小无效时为0
319 /// </summary>
320 public long FileSize
321 {
322 get
323 {
324 return file_size;
325 }
326 }
327
328 /// <summary>
329 /// 链接模式:
330 /// true 被动模式 [默认]
331 /// false: 主动模式
332 /// </summary>
333 public bool PassiveMode
334 {
335 get
336 {
337 return passive_mode;
338 }
339 set
340 {
341 passive_mode = value;
342 }
343 }
344
345 #endregion
346
347 #region 操作
348
349 /// <summary>
350 /// 操作失败
351 /// </summary>
352 private void Fail()
353 {
354 Disconnect();
355 errormessage += responseStr;
356 //throw new Exception(responseStr);
357 }
358
359 /// <summary>
360 /// 下载文件类型
361 /// </summary>
362 /// <param name="mode">true:二进制文件 false:字符文件</param>
363 private void SetBinaryMode(bool mode)
364 {
365 if (mode)
366 SendCommand("TYPE I");
367 else
368 SendCommand("TYPE A");
369
370 ReadResponse();
371 if (response != 200)
372 Fail();
373 }
374
375 /// <summary>
376 /// 发送命令
377 /// </summary>
378 /// <param name="command"></param>
379 private void SendCommand(string command)
380 {
381 Byte[] cmd = Encoding.ASCII.GetBytes((command + "\r\n").ToCharArray());
382
383 if (command.Length > 3 && command.Substring(0, 4) == "PASS")
384 {
385 messages = "\rPASS xxx";
386 }
387 else
388 {
389 messages = "\r" + command;
390 }
391
392 try
393 {
394 main_sock.Send(cmd, cmd.Length, 0);
395 }
396 catch (Exception ex)
397 {
398 try
399 {
400 Disconnect();
401 errormessage += ex.Message;
402 return;
403 }
404 catch
405 {
406 if (main_sock != null)
407 {
408 main_sock.Close();
409 file.Close();
410 main_sock = null;
411 main_ipEndPoint = null;
412 file = null;
413 }
414 }
415 }
416 }
417
418
419 private void FillBucket()
420 {
421 Byte[] bytes = new Byte[512];
422 long bytesgot;
423 int msecs_passed = 0;
424
425 if (main_sock == null)
426 {
427 Disconnect();
428 bucket += "\n";
429 errormessage += "main_sock is lost.";
430 return;
431 }
432
433 while (main_sock.Available < 1)
434 {
435 System.Threading.Thread.Sleep(50);
436 msecs_passed += 50;
437 //当等待时间到,则断开链接
438 if (msecs_passed > timeout)
439 {
440 Disconnect();
441 errormessage += "Timed out waiting on server to respond.";
442 return;
443 }
444 }
445
446 while (main_sock.Available > 0)
447 {
448 bytesgot = main_sock.Receive(bytes, 512, 0);
449 bucket += Encoding.ASCII.GetString(bytes, 0, (int)bytesgot);
450 System.Threading.Thread.Sleep(50);
451 }
452 }
453
454
455 private string GetLineFromBucket()
456 {
457 int i;
458 string buf = "";
459
460 if ((i = bucket.IndexOf('\n')) < 0)
461 {
462 while (i < 0)
463 {
464 FillBucket();
465 i = bucket.IndexOf('\n');
466 }
467 }
468
469 buf = bucket.Substring(0, i);
470 bucket = bucket.Substring(i + 1);
471
472 return buf;
473 }
474
475
476 /// <summary>
477 /// 返回服务器端返回信息
478 /// </summary>
479 private void ReadResponse()
480 {
481 string buf;
482 messages = "";
483
484 while (true)
485 {
486 if (main_sock == null)
487 {
488 response = 0;
489 break;
490 }
491 buf = GetLineFromBucket();
492
493 if (Regex.Match(buf, "^[0-9]+ ").Success)
494 {
495 responseStr = buf;
496 response = int.Parse(buf.Substring(0, 3));
497 break;
498 }
499 else
500 messages += Regex.Replace(buf, "^[0-9]+-", "") + "\n";
501 }
502 }
503
504
505 /// <summary>
506 /// 打开数据套接字
507 /// </summary>
508 private void OpenDataSocket()
509 {
510 if (passive_mode)
511 {
512 string[] pasv;
513 string server;
514 int port;
515
516 Connect();
517 SendCommand("PASV");
518 ReadResponse();
519 if (response != 227)
520 Fail();
521
522 try
523 {
524 int i1, i2;
525
526 i1 = responseStr.IndexOf('(') + 1;
527 i2 = responseStr.IndexOf(')') - i1;
528 pasv = responseStr.Substring(i1, i2).Split(',');
529 }
530 catch (Exception)
531 {
532 Disconnect();
533 errormessage += "Malformed PASV response: " + responseStr;
534 return;
535 }
536
537 if (pasv.Length < 6)
538 {
539 Disconnect();
540 errormessage += "Malformed PASV response: " + responseStr;
541 return;
542 }
543
544 server = String.Format("{0}.{1}.{2}.{3}", pasv[0], pasv[1], pasv[2], pasv[3]);
545 port = (int.Parse(pasv[4]) << 8) + int.Parse(pasv[5]);
546
547 try
548 {
549 CloseDataSocket();
550
551 data_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
552
553 #if NET1
554 data_ipEndPoint = new IPEndPoint(Dns.GetHostByName(server).AddressList[0], port);
555 #else
556 data_ipEndPoint = new IPEndPoint(System.Net.Dns.GetHostEntry(server).AddressList[0], port);
557 #endif
558
559 data_sock.Connect(data_ipEndPoint);
560
561 }
562 catch (Exception ex)
563 {
564 errormessage += "Failed to connect for data transfer: " + ex.Message;
565 return;
566 }
567 }
568 else
569 {
570 Connect();
571
572 try
573 {
574 CloseDataSocket();
575
576 listening_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
577
578 // 对于端口,则发送IP地址.下面则提取相应信息
579 string sLocAddr = main_sock.LocalEndPoint.ToString();
580 int ix = sLocAddr.IndexOf(':');
581 if (ix < 0)
582 {
583 errormessage += "Failed to parse the local address: " + sLocAddr;
584 return;
585 }
586 string sIPAddr = sLocAddr.Substring(0, ix);
587 // 系统自动绑定一个端口号(设置 port = 0)
588 System.Net.IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(sIPAddr), 0);
589
590 listening_sock.Bind(localEP);
591 sLocAddr = listening_sock.LocalEndPoint.ToString();
592 ix = sLocAddr.IndexOf(':');
593 if (ix < 0)
594 {
595 errormessage += "Failed to parse the local address: " + sLocAddr;
596
597 }
598 int nPort = int.Parse(sLocAddr.Substring(ix + 1));
599
600 // 开始侦听链接请求
601 listening_sock.Listen(1);
602 string sPortCmd = string.Format("PORT {0},{1},{2}",
603 sIPAddr.Replace('.', ','),
604 nPort / 256, nPort % 256);
605 SendCommand(sPortCmd);
606 ReadResponse();
607 if (response != 200)
608 Fail();
609 }
610 catch (Exception ex)
611 {
612 errormessage += "Failed to connect for data transfer: " + ex.Message;
613 return;
614 }
615 }
616 }
617
618
619 private void ConnectDataSocket()
620 {
621 if (data_sock != null) // 已链接
622 return;
623
624 try
625 {
626 data_sock = listening_sock.Accept(); // Accept is blocking
627 listening_sock.Close();
628 listening_sock = null;
629
630 if (data_sock == null)
631 {
632 throw new Exception("Winsock error: " +
633 Convert.ToString(System.Runtime.InteropServices.Marshal.GetLastWin32Error()));
634 }
635 }
636 catch (Exception ex)
637 {
638 errormessage += "Failed to connect for data transfer: " + ex.Message;
639 }
640 }
641
642
643 private void CloseDataSocket()
644 {
645 if (data_sock != null)
646 {
647 if (data_sock.Connected)
648 {
649 data_sock.Close();
650 }
651 data_sock = null;
652 }
653
654 data_ipEndPoint = null;
655 }
656
657 /// <summary>
658 /// 关闭所有链接
659 /// </summary>
660 public void Disconnect()
661 {
662 CloseDataSocket();
663
664 if (main_sock != null)
665 {
666 if (main_sock.Connected)
667 {
668 SendCommand("QUIT");
669 main_sock.Close();
670 }
671 main_sock = null;
672 }
673
674 if (file != null)
675 file.Close();
676
677 main_ipEndPoint = null;
678 file = null;
679 }
680
681 /// <summary>
682 /// 链接到FTP服务器
683 /// </summary>
684 /// <param name="server">要链接的IP地址或主机名</param>
685 /// <param name="port">端口号</param>
686 /// <param name="user">登陆帐号</param>
687 /// <param name="pass">登陆口令</param>
688 public void Connect(string server, int port, string user, string pass)
689 {
690 this.server = server;
691 this.user = user;
692 this.pass = pass;
693 this.port = port;
694
695 Connect();
696 }
697
698 /// <summary>
699 /// 链接到FTP服务器
700 /// </summary>
701 /// <param name="server">要链接的IP地址或主机名</param>
702 /// <param name="user">登陆帐号</param>
703 /// <param name="pass">登陆口令</param>
704 public void Connect(string server, string user, string pass)
705 {
706 this.server = server;
707 this.user = user;
708 this.pass = pass;
709
710 Connect();
711 }
712
713 /// <summary>
714 /// 链接到FTP服务器
715 /// </summary>
716 public bool Connect()
717 {
718 if (server == null)
719 {
720 errormessage += "No server has been set.\r\n";
721 }
722 if (user == null)
723 {
724 errormessage += "No server has been set.\r\n";
725 }
726
727 if (main_sock != null)
728 if (main_sock.Connected)
729 return true;
730
731 try
732 {
733 main_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
734 #if NET1
735 main_ipEndPoint = new IPEndPoint(Dns.GetHostByName(server).AddressList[0], port);
736 #else
737 main_ipEndPoint = new IPEndPoint(System.Net.Dns.GetHostEntry(server).AddressList[0], port);
738 #endif
739
740 main_sock.Connect(main_ipEndPoint);
741 }
742 catch (Exception ex)
743 {
744 errormessage += ex.Message;
745 return false;
746 }
747
748 ReadResponse();
749 if (response != 220)
750 Fail();
751
752 SendCommand("USER " + user);
753 ReadResponse();
754
755 switch (response)
756 {
757 case 331:
758 if (pass == null)
759 {
760 Disconnect();
761 errormessage += "No password has been set.";
762 return false;
763 }
764 SendCommand("PASS " + pass);
765 ReadResponse();
766 if (response != 230)
767 {
768 Fail();
769 return false;
770 }
771 break;
772 case 230:
773 break;
774 }
775
776 return true;
777 }
778
779 /// <summary>
780 /// 获取FTP当前(工作)目录下的文件列表
781 /// </summary>
782 /// <returns>返回文件列表数组</returns>
783 public ArrayList List()
784 {
785 Byte[] bytes = new Byte[512];
786 string file_list = "";
787 long bytesgot = 0;
788 int msecs_passed = 0;
789 ArrayList list = new ArrayList();
790
791 Connect();
792 OpenDataSocket();
793 SendCommand("LIST");
794 ReadResponse();
795
796 switch (response)
797 {
798 case 125:
799 case 150:
800 break;
801 default:
802 CloseDataSocket();
803 throw new Exception(responseStr);
804 }
805 ConnectDataSocket();
806
807 while (data_sock.Available < 1)
808 {
809 System.Threading.Thread.Sleep(50);
810 msecs_passed += 50;
811
812 if (msecs_passed > (timeout / 10))
813 {
814 break;
815 }
816 }
817
818 while (data_sock.Available > 0)
819 {
820 bytesgot = data_sock.Receive(bytes, bytes.Length, 0);
821 file_list += Encoding.ASCII.GetString(bytes, 0, (int)bytesgot);
822 System.Threading.Thread.Sleep(50);
823 }
824
825 CloseDataSocket();
826
827 ReadResponse();
828 if (response != 226)
829 throw new Exception(responseStr);
830
831 foreach (string f in file_list.Split('\n'))
832 {
833 if (f.Length > 0 && !Regex.Match(f, "^total").Success)
834 list.Add(f.Substring(0, f.Length - 1));
835 }
836
837 return list;
838 }
839
840 /// <summary>
841 /// 获取到文件名列表
842 /// </summary>
843 /// <returns>返回文件名列表</returns>
844 public ArrayList ListFiles()
845 {
846 ArrayList list = new ArrayList();
847
848 foreach (string f in List())
849 {
850 if ((f.Length > 0))
851 {
852 if ((f[0] != 'd') && (f.ToUpper().IndexOf("<DIR>") < 0))
853 list.Add(f);
854 }
855 }
856
857 return list;
858 }
859
860 /// <summary>
861 /// 获取路径列表
862 /// </summary>
863 /// <returns>返回路径列表</returns>
864 public ArrayList ListDirectories()
865 {
866 ArrayList list = new ArrayList();
867
868 foreach (string f in List())
869 {
870 if (f.Length > 0)
871 {
872 if ((f[0] == 'd') || (f.ToUpper().IndexOf("<DIR>") >= 0))
873 list.Add(f);
874 }
875 }
876
877 return list;
878 }
879
880 /// <summary>
881 /// 获取原始数据信息.
882 /// </summary>
883 /// <param name="fileName">远程文件名</param>
884 /// <returns>返回原始数据信息.</returns>
885 public string GetFileDateRaw(string fileName)
886 {
887 Connect();
888
889 SendCommand("MDTM " + fileName);
890 ReadResponse();
891 if (response != 213)
892 {
893 errormessage += responseStr;
894 return "";
895 }
896
897 return (this.responseStr.Substring(4));
898 }
899
900 /// <summary>
901 /// 得到文件日期.
902 /// </summary>
903 /// <param name="fileName">远程文件名</param>
904 /// <returns>返回远程文件日期</returns>
905 public DateTime GetFileDate(string fileName)
906 {
907 return ConvertFTPDateToDateTime(GetFileDateRaw(fileName));
908 }
909
910 private DateTime ConvertFTPDateToDateTime(string input)
911 {
912 if (input.Length < 14)
913 throw new ArgumentException("Input Value for ConvertFTPDateToDateTime method was too short.");
914
915 //YYYYMMDDhhmmss":
916 int year = Convert.ToInt16(input.Substring(0, 4));
917 int month = Convert.ToInt16(input.Substring(4, 2));
918 int day = Convert.ToInt16(input.Substring(6, 2));
919 int hour = Convert.ToInt16(input.Substring(8, 2));
920 int min = Convert.ToInt16(input.Substring(10, 2));
921 int sec = Convert.ToInt16(input.Substring(12, 2));
922
923 return new DateTime(year, month, day, hour, min, sec);
924 }
925
926 /// <summary>
927 /// 获取FTP上的当前(工作)路径
928 /// </summary>
929 /// <returns>返回FTP上的当前(工作)路径</returns>
930 public string GetWorkingDirectory()
931 {
932 //PWD - 显示工作路径
933 Connect();
934 SendCommand("PWD");
935 ReadResponse();
936
937 if (response != 257)
938 {
939 errormessage += responseStr;
940 }
941
942 string pwd;
943 try
944 {
945 pwd = responseStr.Substring(responseStr.IndexOf("\"", 0) + 1);//5);
946 pwd = pwd.Substring(0, pwd.LastIndexOf("\""));
947 pwd = pwd.Replace("\"\"", "\""); // 替换带引号的路径信息符号
948 }
949 catch (Exception ex)
950 {
951 errormessage += ex.Message;
952 return null;
953 }
954
955 return pwd;
956 }
957
958
959 /// <summary>
960 /// 跳转服务器上的当前(工作)路径
961 /// </summary>
962 /// <param name="path">要跳转的路径</param>
963 public bool ChangeDir(string path)
964 {
965 Connect();
966 SendCommand("CWD " + path);
967 ReadResponse();
968 if (response != 250)
969 {
970 errormessage += responseStr;
971 return false;
972 }
973 return true;
974 }
975
976 /// <summary>
977 /// 创建指定的目录
978 /// </summary>
979 /// <param name="dir">要创建的目录</param>
980 public void MakeDir(string dir)
981 {
982 Connect();
983 SendCommand("MKD " + dir);
984 ReadResponse();
985
986 switch (response)
987 {
988 case 257:
989 case 250:
990 break;
991 default:
992 {
993 errormessage += responseStr;
994 break;
995 }
996 }
997 }
998
999 /// <summary>
1000 /// 移除FTP上的指定目录
1001 /// </summary>
1002 /// <param name="dir">要移除的目录</param>
1003 public void RemoveDir(string dir)
1004 {
1005 Connect();
1006 SendCommand("RMD " + dir);
1007 ReadResponse();
1008 if (response != 250)
1009 {
1010 errormessage += responseStr;
1011 return; ;
1012 }
1013 }
1014
1015 /// <summary>
1016 /// 移除FTP上的指定文件
1017 /// </summary>
1018 /// <param name="filename">要移除的文件名称</param>
1019 public void RemoveFile(string filename)
1020 {
1021 Connect();
1022 SendCommand("DELE " + filename);
1023 ReadResponse();
1024 if (response != 250)
1025 {
1026 errormessage += responseStr;
1027 }
1028 }
1029
1030 /// <summary>
1031 /// 重命名FTP上的文件
1032 /// </summary>
1033 /// <param name="oldfilename">原文件名</param>
1034 /// <param name="newfilename">新文件名</param>
1035 public void RenameFile(string oldfilename, string newfilename)
1036 {
1037 Connect();
1038 SendCommand("RNFR " + oldfilename);
1039 ReadResponse();
1040 if (response != 350)
1041 {
1042 errormessage += responseStr;
1043 }
1044 else
1045 {
1046 SendCommand("RNTO " + newfilename);
1047 ReadResponse();
1048 if (response != 250)
1049 {
1050 errormessage += responseStr;
1051 }
1052 }
1053 }
1054
1055 /// <summary>
1056 /// 获得指定文件的大小(如果FTP支持)
1057 /// </summary>
1058 /// <param name="filename">指定的文件</param>
1059 /// <returns>返回指定文件的大小</returns>
1060 public long GetFileSize(string filename)
1061 {
1062 Connect();
1063 SendCommand("SIZE " + filename);
1064 ReadResponse();
1065 if (response != 213)
1066 {
1067 errormessage += responseStr;
1068 }
1069
1070 return Int64.Parse(responseStr.Substring(4));
1071 }
1072
1073 /// <summary>
1074 /// 上传指定的文件
1075 /// </summary>
1076 /// <param name="filename">要上传的文件</param>
1077 public bool OpenUpload(string filename)
1078 {
1079 return OpenUpload(filename, filename, false);
1080 }
1081
1082 /// <summary>
1083 /// 上传指定的文件
1084 /// </summary>
1085 /// <param name="filename">本地文件名</param>
1086 /// <param name="remotefilename">远程要覆盖的文件名</param>
1087 public bool OpenUpload(string filename, string remotefilename)
1088 {
1089 return OpenUpload(filename, remotefilename, false);
1090 }
1091
1092 /// <summary>
1093 /// 上传指定的文件
1094 /// </summary>
1095 /// <param name="filename">本地文件名</param>
1096 /// <param name="resume">如果存在,则尝试恢复</param>
1097 public bool OpenUpload(string filename, bool resume)
1098 {
1099 return OpenUpload(filename, filename, resume);
1100 }
1101
1102 /// <summary>
1103 /// 上传指定的文件
1104 /// </summary>
1105 /// <param name="filename">本地文件名</param>
1106 /// <param name="remote_filename">远程要覆盖的文件名</param>
1107 /// <param name="resume">如果存在,则尝试恢复</param>
1108 public bool OpenUpload(string filename, string remote_filename, bool resume)
1109 {
1110 Connect();
1111 SetBinaryMode(true);
1112 OpenDataSocket();
1113
1114 bytes_total = 0;
1115
1116 try
1117 {
1118 file = new FileStream(filename, FileMode.Open);
1119 }
1120 catch (Exception ex)
1121 {
1122 file = null;
1123 errormessage += ex.Message;
1124 return false;
1125 }
1126
1127 file_size = file.Length;
1128
1129 if (resume)
1130 {
1131 long size = GetFileSize(remote_filename);
1132 SendCommand("REST " + size);
1133 ReadResponse();
1134 if (response == 350)
1135 file.Seek(size, SeekOrigin.Begin);
1136 }
1137
1138 SendCommand("STOR " + remote_filename);
1139 ReadResponse();
1140
1141 switch (response)
1142 {
1143 case 125:
1144 case 150:
1145 break;
1146 default:
1147 if (file != null)
1148 {
1149 file.Close();
1150 file = null;
1151 }
1152 errormessage += responseStr;
1153 return false;
1154 }
1155 ConnectDataSocket();
1156
1157 return true;
1158 }
1159
1160 /// <summary>
1161 /// 下载指定文件
1162 /// </summary>
1163 /// <param name="filename">远程文件名称</param>
1164 public void OpenDownload(string filename)
1165 {
1166 OpenDownload(filename, filename, false);
1167 }
1168
1169 /// <summary>
1170 /// 下载并恢复指定文件
1171 /// </summary>
1172 /// <param name="filename">远程文件名称</param>
1173 /// <param name="resume">如文件存在,则尝试恢复</param>
1174 public void OpenDownload(string filename, bool resume)
1175 {
1176 OpenDownload(filename, filename, resume);
1177 }
1178
1179 /// <summary>
1180 /// 下载指定文件
1181 /// </summary>
1182 /// <param name="filename">远程文件名称</param>
1183 /// <param name="localfilename">本地文件名</param>
1184 public void OpenDownload(string remote_filename, string localfilename)
1185 {
1186 OpenDownload(remote_filename, localfilename, false);
1187 }
1188
1189 /// <summary>
1190 /// 打开并下载文件
1191 /// </summary>
1192 /// <param name="remote_filename">远程文件名称</param>
1193 /// <param name="local_filename">本地文件名</param>
1194 /// <param name="resume">如果文件存在则恢复</param>
1195 public void OpenDownload(string remote_filename, string local_filename, bool resume)
1196 {
1197 Connect();
1198 SetBinaryMode(true);
1199
1200 bytes_total = 0;
1201
1202 try
1203 {
1204 file_size = GetFileSize(remote_filename);
1205 }
1206 catch
1207 {
1208 file_size = 0;
1209 }
1210
1211 if (resume && File.Exists(local_filename))
1212 {
1213 try
1214 {
1215 file = new FileStream(local_filename, FileMode.Open);
1216 }
1217 catch (Exception ex)
1218 {
1219 file = null;
1220 throw new Exception(ex.Message);
1221 }
1222
1223 SendCommand("REST " + file.Length);
1224 ReadResponse();
1225 if (response != 350)
1226 throw new Exception(responseStr);
1227 file.Seek(file.Length, SeekOrigin.Begin);
1228 bytes_total = file.Length;
1229 }
1230 else
1231 {
1232 try
1233 {
1234 file = new FileStream(local_filename, FileMode.Create);
1235 }
1236 catch (Exception ex)
1237 {
1238 file = null;
1239 throw new Exception(ex.Message);
1240 }
1241 }
1242
1243 OpenDataSocket();
1244 SendCommand("RETR " + remote_filename);
1245 ReadResponse();
1246
1247 switch (response)
1248 {
1249 case 125:
1250 case 150:
1251 break;
1252 default:
1253 file.Close();
1254 file = null;
1255 errormessage += responseStr;
1256 return;
1257 }
1258 ConnectDataSocket();
1259
1260 return;
1261 }
1262
1263 /// <summary>
1264 /// 上传文件(循环调用直到上传完毕)
1265 /// </summary>
1266 /// <returns>发送的字节数</returns>
1267 public long DoUpload()
1268 {
1269 Byte[] bytes = new Byte[512];
1270 long bytes_got;
1271
1272 try
1273 {
1274 bytes_got = file.Read(bytes, 0, bytes.Length);
1275 bytes_total += bytes_got;
1276 data_sock.Send(bytes, (int)bytes_got, 0);
1277
1278 if (bytes_got <= 0)
1279 {
1280 //上传完毕或有错误发生
1281 file.Close();
1282 file = null;
1283
1284 CloseDataSocket();
1285 ReadResponse();
1286 switch (response)
1287 {
1288 case 226:
1289 case 250:
1290 break;
1291 default: //当上传中断时
1292 {
1293 errormessage += responseStr;
1294 return -1;
1295 }
1296 }
1297
1298 SetBinaryMode(false);
1299 }
1300 }
1301 catch (Exception ex)
1302 {
1303 file.Close();
1304 file = null;
1305 CloseDataSocket();
1306 ReadResponse();
1307 SetBinaryMode(false);
1308 //throw ex;
1309 //当上传中断时
1310 errormessage += ex.Message;
1311 return -1;
1312 }
1313
1314 return bytes_got;
1315 }
1316
1317 /// <summary>
1318 /// 下载文件(循环调用直到下载完毕)
1319 /// </summary>
1320 /// <returns>接收到的字节点</returns>
1321 public long DoDownload()
1322 {
1323 Byte[] bytes = new Byte[512];
1324 long bytes_got;
1325
1326 try
1327 {
1328 bytes_got = data_sock.Receive(bytes, bytes.Length, 0);
1329
1330 if (bytes_got <= 0)
1331 {
1332 //下载完毕或有错误发生
1333 CloseDataSocket();
1334 file.Close();
1335 file = null;
1336
1337 ReadResponse();
1338 switch (response)
1339 {
1340 case 226:
1341 case 250:
1342 break;
1343 default:
1344 {
1345 errormessage += responseStr;
1346 return -1;
1347 }
1348 }
1349
1350 SetBinaryMode(false);
1351
1352 return bytes_got;
1353 }
1354
1355 file.Write(bytes, 0, (int)bytes_got);
1356 bytes_total += bytes_got;
1357 }
1358 catch (Exception ex)
1359 {
1360 CloseDataSocket();
1361 file.Close();
1362 file = null;
1363 ReadResponse();
1364 SetBinaryMode(false);
1365 //throw ex;
1366 //当下载中断时
1367 errormessage += ex.Message;
1368 return -1;
1369 }
1370
1371 return bytes_got;
1372 }
1373
1374 #endregion
1375
1376
1377 }
1378 }
1379

 

我用的多线程方式是在多线程调用的方法了,声明ftp实例,然后批量上传文件代码如下

 

代码
1 private void UpFileWork()
2 {
3 private Ftp_Socket fs = new Ftp_Socket(ftpip, ftpport, ftpuser, ftppass);
4 try
5 {
6 while (true)
7 {
8 #region 获取共享资源,上传的文件路径
9 lock (picModelList)
10 {
11 if (picModelList.Count > 0)
12 {
13 tmp = picModelList[0];
14 picModelList.Remove(tmp);
15 }
16 else
17 {
18 tmp = null;
19 }
20 }
21 #endregion
22 if (tmp == null)
23 {
24 System.Threading.Thread.Sleep(180000);
25 }
26 else
27 {
28 #region 分析路径
29 //最后得到两个路径一个本地路径,一个服务器的相对路径
30 string filePath=....//本地路径
31 string upFilePath=...//服务器相对路径
32 #endregion
33
34 #region 上传
35
36 fs.ChangeDir("/");
37 string folderName = upFilePath.Substring(0, upFilePath.LastIndexOf(@"/")).Replace(upFilePath, "");
38 string[] chkfolder = folderName.Split('/');
39
40 if (!fs.ChangeDir(folderName))
41 {
42 for (int i = 0; i <= chkfolder.Length - 1; i++)
43 {
44 if (chkfolder[i].Trim() != string.Empty)
45 {
46 fs.MakeDir(chkfolder[i]);
47 fs.ChangeDir(chkfolder[i]);
48 }
49 }
50 }
51 string filename = upFilePath.Substring(upFilePath.LastIndexOf(@"/") + 1);
52 fs.Connect();
53 if (!fs.OpenUpload(filePath, filename))
54 {
55 fs.Disconnect();
56 //做错误处理
57 }
58 int perc = 0;
59 while (fs.DoUpload() > 0)
60 {
61 perc = (int)(((fs.BytesTotal) * 100) / fs.FileSize);
62 }
63 if (perc >= 100)
64 {
65 //做正确处理
66 }
67 else
68 {
69 //做错误处理
70 }
71 #endregion
72 lock (picbll)
73 {
74 picbll.Update(tmp);
75 }
76 }
77 }
78 }
79 catch
80 {
81 uf.DisConnect();
82 }
83 }

 

问题

目前开始运行的时候没有问题,当运行一段时间之后,有部分线程会经常卡住不动,经分析,大概是在ftp做连接数据socket的时候发生一直等待现象,是ftp类的这个函数ConnectDataSocket()里的这句代码 data_sock = listening_sock.Accept();    // Accept is blocking

我又在代码里加了listening_sock的超时时间,但貌似还是不行

listening_sock.ReceiveTimeout = 30000;
                    listening_sock.SendTimeout = 30000;

 

求高手分析,不胜感激.

问题补充: 能不能刷到上边?
卡蒙的主页 卡蒙 | 初学一级 | 园豆:135
提问于:2010-12-18 16:40
< >
分享
所有回答(1)
0

会不会是服务器那边有什么限制?另外 .net 有封装好的 FTP 类,我不知道为什么你要自己造这个轮子,你直接用 .net 的

FtpWebRequest 来实现就可以了。

http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.aspx

http://www.cnblogs.com/webabcd/archive/2007/01/21/626242.html

eaglet | 园豆:17119 (专家六级) | 2010-12-20 05:24
我不知道是我用的不对,还是怎么回事,我采用FtpWebRequest的方法上传 效率极其低下,因为文件都在不同的文件夹,而且目录很深有个4\5级目录,每个目录里只有两三个文件,每次都用创建目录,然后上传,而FtpWebRequest 貌似没有提供改变文件目录的方法,只能每创建一个重新连接一次,导致大部分时间都在验证用户名,创建连接,我是这样认为的,不知道对不对,所以就用了Discuz.net版里的这个socket类
支持(0) 反对(0) 卡蒙 | 园豆:135 (初学一级) | 2010-12-20 11:14
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册