网络课程设计-MKFTP v1.0 Server + ClientBrower
目前只实现了课程设计要求的几个功能:
1. get remote-file [local-file] :从Server下载的一个文件
2. put local-file [remote-file] :传给Server一个文件
3. pwd :显示Server当前目录
4. dir :列出Server当前目录
5. cd directory :改变Server当前目录
6. ? [command] :显示所提供的命令
7. quit :退出返回
代码未经整理,呵呵,等寒假再回来重构一下.
1. get remote-file [local-file] :从Server下载的一个文件
2. put local-file [remote-file] :传给Server一个文件
3. pwd :显示Server当前目录
4. dir :列出Server当前目录
5. cd directory :改变Server当前目录
6. ? [command] :显示所提供的命令
7. quit :退出返回
FtpServer.MainApp
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.IO;
5using System.Net;
6using System.Net.Sockets;
7using System.Threading;
8
9namespace FtpServer
10{
11 public class MainApp
12 {
13 public static string FtpRoot = @"E:\FTP";
14
15 public static void getHelp()
16 {
17 Console.WriteLine("Ftp help:");
18 Console.WriteLine("-r [path]\t:\tChange FTP Root");
19 Console.WriteLine("-? \t:\tGet Help");
20 }
21
22 public static void Main(string[] args)
23 {
24 for (int i = 0; i < args.Length; i++)
25 {
26 switch (args[i])
27 {
28 case "-r":
29 FtpRoot = args[i + 1];
30 break;
31 case "-?":
32 getHelp();
33 break;
34 default:
35
36 FtpRoot = Directory.GetCurrentDirectory();
37 break;
38 }
39 }
40 Console.WriteLine("FTP server Start");
41 //创建一个FTP对象
42 Ftp ftp = new Ftp();
43 //启动Ftp
44 if (ftp.Start() == false)
45 {
46 Console.WriteLine("Failed to start FTP Server.");
47 }
48 }
49 }
50}
51
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.IO;
5using System.Net;
6using System.Net.Sockets;
7using System.Threading;
8
9namespace FtpServer
10{
11 public class MainApp
12 {
13 public static string FtpRoot = @"E:\FTP";
14
15 public static void getHelp()
16 {
17 Console.WriteLine("Ftp help:");
18 Console.WriteLine("-r [path]\t:\tChange FTP Root");
19 Console.WriteLine("-? \t:\tGet Help");
20 }
21
22 public static void Main(string[] args)
23 {
24 for (int i = 0; i < args.Length; i++)
25 {
26 switch (args[i])
27 {
28 case "-r":
29 FtpRoot = args[i + 1];
30 break;
31 case "-?":
32 getHelp();
33 break;
34 default:
35
36 FtpRoot = Directory.GetCurrentDirectory();
37 break;
38 }
39 }
40 Console.WriteLine("FTP server Start");
41 //创建一个FTP对象
42 Ftp ftp = new Ftp();
43 //启动Ftp
44 if (ftp.Start() == false)
45 {
46 Console.WriteLine("Failed to start FTP Server.");
47 }
48 }
49 }
50}
51
FtpServer.SessionInfo
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.IO;
5using System.Net;
6using System.Net.Sockets;
7using System.Threading;
8
9namespace FtpServer
10{
11 public class SessionInfo
12 {
13 private bool _binary;
14
15 public bool Binary
16 {
17 get { return _binary; }
18 set { _binary = value; }
19 }
20 private bool _passive;
21
22 public bool Passive
23 {
24 get { return _passive; }
25 set { _passive = value; }
26 }
27 private string _ftpRoot;
28
29 public string FtpRoot
30 {
31 get { return _ftpRoot; }
32 set { _ftpRoot = value; }
33 }
34 private string _userName;
35
36 public string UserName
37 {
38 get { return _userName; }
39 set { _userName = value; }
40 }
41 private PassiveInfo _passiveInfo;
42
43 public PassiveInfo PassiveInfo
44 {
45 get { return _passiveInfo; }
46 set { _passiveInfo = value; }
47 }
48
49 private IPEndPoint _remoteEP;
50
51 public IPEndPoint RemoteEP
52 {
53 get { return _remoteEP; }
54 set { _remoteEP = value; }
55 }
56
57 private string _username = "";
58
59 public string Username
60 {
61 get { return _username; }
62 set { _username = value; }
63 }
64 private string _password = "";
65
66 public string Password
67 {
68 get { return _password; }
69 set { _password = value; }
70 }
71
72 public SessionInfo()
73 {
74 _binary = true;
75 _passive = true;
76 _ftpRoot = MainApp.FtpRoot;
77 _userName = "";
78 _passiveInfo = new PassiveInfo();
79 _remoteEP = null;
80 }
81 }
82
83 public class PassiveInfo
84 {
85 private IPHostEntry _IPHostEntry;
86
87 public IPHostEntry IPHostEntry
88 {
89 get { return _IPHostEntry; }
90 set { _IPHostEntry = value; }
91 }
92 private TcpListener _tcpListener;
93
94 public TcpListener TcpListener
95 {
96 get { return _tcpListener; }
97 set { _tcpListener = value; }
98 }
99 private IPEndPoint _remoteEP;
100
101 public IPEndPoint RemoteEP
102 {
103 get { return _remoteEP; }
104 set { _remoteEP = value; }
105 }
106
107 public PassiveInfo()
108 {
109 _IPHostEntry = null;
110 _tcpListener = null;
111 _remoteEP = null;
112 }
113
114 public PassiveInfo(IPHostEntry host, TcpListener listener, IPEndPoint remoteEP)
115 {
116 _IPHostEntry = host;
117 _tcpListener = listener;
118 _remoteEP = remoteEP;
119 }
120 }
121}
122
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.IO;
5using System.Net;
6using System.Net.Sockets;
7using System.Threading;
8
9namespace FtpServer
10{
11 public class SessionInfo
12 {
13 private bool _binary;
14
15 public bool Binary
16 {
17 get { return _binary; }
18 set { _binary = value; }
19 }
20 private bool _passive;
21
22 public bool Passive
23 {
24 get { return _passive; }
25 set { _passive = value; }
26 }
27 private string _ftpRoot;
28
29 public string FtpRoot
30 {
31 get { return _ftpRoot; }
32 set { _ftpRoot = value; }
33 }
34 private string _userName;
35
36 public string UserName
37 {
38 get { return _userName; }
39 set { _userName = value; }
40 }
41 private PassiveInfo _passiveInfo;
42
43 public PassiveInfo PassiveInfo
44 {
45 get { return _passiveInfo; }
46 set { _passiveInfo = value; }
47 }
48
49 private IPEndPoint _remoteEP;
50
51 public IPEndPoint RemoteEP
52 {
53 get { return _remoteEP; }
54 set { _remoteEP = value; }
55 }
56
57 private string _username = "";
58
59 public string Username
60 {
61 get { return _username; }
62 set { _username = value; }
63 }
64 private string _password = "";
65
66 public string Password
67 {
68 get { return _password; }
69 set { _password = value; }
70 }
71
72 public SessionInfo()
73 {
74 _binary = true;
75 _passive = true;
76 _ftpRoot = MainApp.FtpRoot;
77 _userName = "";
78 _passiveInfo = new PassiveInfo();
79 _remoteEP = null;
80 }
81 }
82
83 public class PassiveInfo
84 {
85 private IPHostEntry _IPHostEntry;
86
87 public IPHostEntry IPHostEntry
88 {
89 get { return _IPHostEntry; }
90 set { _IPHostEntry = value; }
91 }
92 private TcpListener _tcpListener;
93
94 public TcpListener TcpListener
95 {
96 get { return _tcpListener; }
97 set { _tcpListener = value; }
98 }
99 private IPEndPoint _remoteEP;
100
101 public IPEndPoint RemoteEP
102 {
103 get { return _remoteEP; }
104 set { _remoteEP = value; }
105 }
106
107 public PassiveInfo()
108 {
109 _IPHostEntry = null;
110 _tcpListener = null;
111 _remoteEP = null;
112 }
113
114 public PassiveInfo(IPHostEntry host, TcpListener listener, IPEndPoint remoteEP)
115 {
116 _IPHostEntry = host;
117 _tcpListener = listener;
118 _remoteEP = remoteEP;
119 }
120 }
121}
122
FtpServer.Ftp
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.IO;
5using System.Net;
6using System.Net.Sockets;
7using System.Threading;
8using System.Globalization;
9
10namespace FtpServer
11{
12 public class Ftp
13 {
14 private TcpListener _tcpListener;
15 private Socket _socket;
16 private IPHostEntry _IPHostEntry;
17 private IPEndPoint _IPEndPoint;
18
19 public Ftp()
20 {
21 _IPHostEntry = Dns.GetHostEntry(Dns.GetHostName());
22 _IPEndPoint = new IPEndPoint(_IPHostEntry.AddressList[0], 21);
23 _tcpListener = new TcpListener(_IPEndPoint);
24 }
25
26 public bool Start()
27 {
28 try
29 {
30 _tcpListener.Start();
31 while (true)
32 {
33 //接收到客户端的一个连接请求,返回一个Socket响应它,采用多线程方式,支持多用户同时访问
34 //此Socket是处理用户的控制连接
35 _socket = _tcpListener.AcceptSocket();
36 Thread client = new Thread(new ThreadStart(ServerConnection));
37 client.Start();
38 }
39 }
40 catch (SocketException se)
41 {
42 Console.WriteLine("Error: {0}", se.Message);
43 return false;
44 }
45 }
46
47 public void Reply(Socket socket, int responseCode, string message)
48 {
49 try
50 {
51 string response = responseCode + " " + message + "\r\n";
52 byte[] datas = GetBytes(response);
53 socket.Send(datas);
54 }
55 catch (Exception e)
56 {
57 Console.WriteLine(e.Message);
58 }
59 }
60
61 private byte[] GetBytes(string response)
62 {
63 return GetBytes(response, Encoding.Default);
64 }
65
66 private byte[] GetBytes(string response, Encoding encoder)
67 {
68 return encoder.GetBytes(response);
69 }
70
71 private string GetString(byte[] datas, int offset, int size)
72 {
73 return GetString(datas, offset, size, Encoding.Default);
74 }
75
76 private string GetString(byte[] datas, int offset, int size, Encoding encoder)
77 {
78 return encoder.GetString(datas, offset, size);
79 }
80
81 /**//// <summary>
82 /// 处理一个连接请求
83 /// </summary>
84 private void ServerConnection()
85 {
86 //这里需要互斥访问??
87 Socket socket = _socket;
88 //建立一个新会话
89 SessionInfo session = new SessionInfo();
90 session.RemoteEP = (IPEndPoint)socket.RemoteEndPoint;
91 //显示服务器信息
92 string message = "Welcome to MK FTP Server v1.0, Base on .NET Framework 2.0.";
93 Reply(socket, 220, message);
94
95 //分析用户命令
96 CheckCommand(socket, session);
97 }
98
99 private void CheckCommand(Socket socket, SessionInfo session)
100 {
101 try
102 {
103 //循环执行用户命令
104 while (true)
105 {
106 byte[] buffer = new byte[256];
107 //接收命令
108 int dataSize = socket.Receive(buffer);
109 string cmd = GetString(buffer, 0, dataSize).Replace("\r\n", "");
110 string command = "";
111 string parameter = "";
112 if (cmd.Length == 3)
113 command = cmd;
114 else
115 command = cmd.Substring(0, 3);
116 string paras = "";
117 command = command.ToUpper();
118 if (command != "CWD" && command != "PWD")
119 {
120 command = cmd.Substring(0, 4).ToUpper();
121 if (cmd.Length > 4)
122 parameter = cmd.Substring(5);
123 }
124 else
125 {
126 if (cmd.Length > 3)
127 {
128 parameter = cmd.Substring(4);
129 }
130 }
131 //for (int i = 0; i < 4; i++)
132 //{
133 // //不是回车换行符
134 // if (buffer[i] != 0 && buffer[i] != 13 && buffer[i] != 10 && buffer[i] != 32)
135 // {
136 // command += (char)buffer[i];
137 // }
138 //}
139 //if (command != "CWD" && command != "PWD")
140 //{
141 // for (int i = 5; i < buffer.Length; i++)
142 // {
143 // //不是回车换行符
144 // if (buffer[i] != 0 && buffer[i] != 13 && buffer[i] != 10 && buffer[i] != 32)
145 // {
146 // parameter += (char)buffer[i];
147 // }
148 // }
149 //}
150 //else
151 //{
152 // for (int i = 4; i < buffer.Length; i++)
153 // {
154 // //不是回车换行符
155 // if (buffer[i] != 0 && buffer[i] != 13 && buffer[i] != 10 && buffer[i] != 32)
156 // {
157 // parameter += (char)buffer[i];
158 // }
159 // }
160 //}
161 //parameter = parameter.Trim();
162 System.Console.WriteLine("From {0} : {1} {2}", socket.RemoteEndPoint, command, parameter);
163
164 //FTP命令格式:前4位为命令类型,后面为命令参数
165 switch (command)
166 {
167 //用户
168 case "USER":
169 session.UserName = parameter;
170 Reply(socket, 331, "User name okey, need password.");
171 break;
172 //密码
173 case "PASS":
174 session.Password = parameter;
175 AuthenticateUser(socket, session.UserName, session.Password);
176 break;
177 //EPSV 扩展被动模式
178 case "EPSV":
179 Reply(socket, 522, "Extended Passive Mode not supported.");
180 break;
181 //被动模式
182 case "PASV":
183 session.Passive = true;
184 ProcessPassiveCommand(socket, parameter, session);
185 break;
186 //设定主动模式的数据连接端口
187 case "PORT":
188 session.Passive = false;
189 ProcessPortCommand(socket, parameter, session);
190 break;
191 //文件及子目录列表
192 case "LIST":
193 ProcessListCommand(socket, parameter, session);
194 break;
195 //发送客户端下载的文件
196 case "RETR":
197 ProcessRetreiveCommand(socket, parameter, session);
198 break;
199 //名字系统类型
200 case "SYST":
201 Reply(socket, 215, System.Environment.OSVersion.VersionString);
202 break;
203 //上传文件
204 case "STOR":
205 ProcessStoreCommand(socket, parameter, session);
206 break;
207 //改变工作目录
208 case "CWD":
209 ProcessCWDCommand(socket, parameter, session);
210 break;
211 //当前目录
212 case "PWD":
213 ProcessPWDCommand(socket, parameter, session);
214 break;
215 //传输模式
216 case "TYPE":
217 switch (parameter)
218 {
219 case "I":
220 session.Binary = true;
221 Reply(socket, 200, "Type set to I.");
222 break;
223 case "A":
224 session.Binary = false;
225 Reply(socket, 200, "Type set to A.");
226 break;
227 default:
228 Reply(socket, 200, "Type not change.");
229 break;
230 }
231 break;
232 //退出
233 case "QUIT":
234 Reply(socket, 221, "Goodbye!.");
235 socket.Close();
236 return;
237 default:
238 Reply(socket, 502, "'" + command + "': not implemented.");
239 break;
240 }
241 }
242 }
243 catch (Exception e)
244 {
245 Console.WriteLine(e.Message);
246 }
247 }
248
249 private void ProcessPWDCommand(Socket socket, string parameter, SessionInfo session)
250 {
251 Reply(socket, 257, "\"" + session.FtpRoot + "\" is current directory.");
252 }
253
254 private void ProcessCWDCommand(Socket socket, string parameter, SessionInfo session)
255 {
256 if (parameter.IndexOf("\\") > 0 && parameter.IndexOf(":") > 0)
257 {
258 session.FtpRoot = parameter;
259 }
260 else
261 {
262 session.FtpRoot += @"\" + parameter;
263 }
264
265 DirectoryInfo dir = new DirectoryInfo(session.FtpRoot);
266 if (!dir.Exists)
267 {
268 Reply(socket, 550, dir.FullName + ": No such directory.");
269 return;
270 }
271 Reply(socket, 250, "Directory changed to "+dir.FullName);
272 }
273
274 private void ProcessStoreCommand(Socket socket, string parameter, SessionInfo session)
275 {
276 try
277 {
278 string file = session.FtpRoot + @"\" + parameter;
279 FileStream fs = new FileStream(file, FileMode.Create);
280
281 byte[] buffer = new byte[1024];
282
283 int dataSize = 0;
284
285 if (session.Binary)
286 {
287 Reply(socket, 150, "Opening BINARY mode data connection for " + parameter);
288 BinaryWriter bw = new BinaryWriter(fs);
289 Socket binarySocket;
290 if (session.Passive)
291 {
292 binarySocket = session.PassiveInfo.TcpListener.AcceptSocket();
293
294 }
295 else
296 {
297 binarySocket = new Socket(AddressFamily.InterNetwork,
298 SocketType.Stream, ProtocolType.Tcp);
299 binarySocket.Bind(new IPEndPoint(_IPEndPoint.Address, 0));
300 binarySocket.Connect(session.RemoteEP);
301 }
302 while ((dataSize = binarySocket.Receive(buffer)) > 0)
303 {
304 bw.Write(buffer, 0, dataSize);
305 }
306 bw.Close();
307 binarySocket.Close();
308 }
309 else
310 {
311 //FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open);
312 //Reply(socket, 150, "Opening ASCII mode data connection for " + parameter
313 // + " (" + fileInfo.Length + " Bytes).");
314 //StreamReader sr = new StreamReader(fs);
315 //if (session.Passive)
316 //{
317 // SendOverPassiveDataConnection(GetBytes(sr.ReadToEnd(), Encoding.UTF8), session);
318
319 //}
320 //else
321 //{
322 // SendOverDataConnection(GetBytes(sr.ReadToEnd(), Encoding.UTF8), session);
323 //}
324 //sr.Close();
325 //fs.Close();
326 }
327
328 Reply(socket, 226, "Transfer Complete");
329
330 }
331 catch (Exception e)
332 {
333 Console.WriteLine(e.Message);
334 }
335 }
336
337 private void ProcessRetreiveCommand(Socket socket, string parameter, SessionInfo session)
338 {
339 try
340 {
341 string file = session.FtpRoot + @"\" + parameter;
342 FileInfo fileInfo =new FileInfo(file);
343 if (!fileInfo.Exists)
344 {
345 Reply(socket, 550, fileInfo.FullName + ": No such file.");
346 return;
347 }
348 if (session.Binary)
349 {
350 Reply(socket, 150, "Opening BINARY mode data connection for " + parameter
351 + " (" + fileInfo.Length + " Bytes)");
352 //BinaryReader br = new BinaryReader(fs);
353 Socket binarySocket;
354 if (session.Passive)
355 {
356 binarySocket = session.PassiveInfo.TcpListener.AcceptSocket();
357 }
358 else
359 {
360 binarySocket = new Socket(AddressFamily.InterNetwork,
361 SocketType.Stream, ProtocolType.Tcp);
362 binarySocket.Bind(new IPEndPoint(_IPEndPoint.Address, 0));
363 binarySocket.Connect(session.RemoteEP);
364 }
365 //while (br.PeekChar() > -1)
366 //{
367 // binarySocket.Send(br.ReadBytes(10240));
368 // //binarySocket.
369 //}
370 //br.Close();
371 binarySocket.SendFile(fileInfo.FullName);
372 binarySocket.Close();
373 }
374 else
375 {
376 FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open);
377 Reply(socket, 150, "Opening ASCII mode data connection for " + parameter
378 + " (" + fileInfo.Length + " Bytes).");
379 StreamReader sr = new StreamReader(fs);
380 if (session.Passive)
381 {
382 SendOverPassiveDataConnection(GetBytes(sr.ReadToEnd()), session);
383
384 }
385 else
386 {
387 SendOverDataConnection(GetBytes(sr.ReadToEnd()), session);
388 }
389 sr.Close();
390 fs.Close();
391 }
392
393 Reply(socket, 200, "Transfer Complete");
394
395 }
396 catch (Exception e)
397 {
398 Console.WriteLine(e.Message);
399 }
400 }
401
402 private void ProcessListCommand(Socket socket, string parameter, SessionInfo session)
403 {
404 DirectoryInfo curDir = new DirectoryInfo(session.FtpRoot);
405 DirectoryInfo[] dirInfoList = curDir.GetDirectories();
406 FileInfo[] fileSysInfoList = curDir.GetFiles();
407
408 const string s_dir = "\t";//"┼ <DIR> ";
409 const string s_file = "";// "├ ";
410 const string s_d_right = "drw-rw-rw-";
411 const string s_f_right = "_rw-rw-rw-";
412 const string s_1 = " ";
413 const string s_3 = " ";
414 const string s_7 = " ";
415 const string s_10 = " ";
416 StringBuilder sb = new StringBuilder();
417 foreach (DirectoryInfo dir in dirInfoList)
418 {
419 //sb.Append(s_d_right + s_1 + "1 user" + s_1 + "group" + s_1 + 0 + s_1 + dir.LastWriteTime + s_1 + dir.Name);
420 //sb.Append("\r\n");
421 GetFormatRow(sb, s_d_right, 0, dir.LastWriteTime, dir.Name);
422 }
423
424 foreach (FileInfo file in fileSysInfoList)
425 {
426 //sb.Append(s_f_right + s_1 + "1 user" + s_1 + "group" + s_1 + file.Length + s_1 + file.LastWriteTime + s_1 + file.Name);
427 //sb.Append("\r\n");
428 GetFormatRow(sb, s_f_right, file.Length, file.LastWriteTime, file.Name);
429 }
430
431 Reply(socket, 150, "Opening ASCII mode data connection for /bin/ls.");
432 if (session.Passive)
433 {
434 SendOverPassiveDataConnection(GetBytes(sb.ToString()), session);
435 }
436 else
437 {
438 SendOverDataConnection(GetBytes(sb.ToString()), session);
439 }
440 Console.WriteLine("Listed.");
441 //socket.
442 Reply(socket, 226, "Transfer complete.");
443
444 }
445
446 private string GetFormatRow(StringBuilder sb, string right, Int64 size, DateTime date, string name)
447 {
448 const string s_1 = " ";
449 sb.Append(right + s_1);
450 sb.Append("user group ");
451 for (int i = size.ToString().Length; i < 12; i++)
452 {
453 sb.Append(s_1);
454 }
455 sb.Append(size + s_1);
456 sb.Append(date.ToString("MMM d hh:ss ", DateTimeFormatInfo.InvariantInfo));
457 sb.Append(name + "\r\n");
458 return sb.ToString();
459 }
460
461 /**//// <summary>
462 /// 主动模式下传输数据
463 /// </summary>
464 /// <param name="p"></param>
465 private bool SendOverDataConnection(byte[] datas, SessionInfo session)
466 {
467 try
468 {
469 Console.WriteLine("Connecting Client: {0}", session.RemoteEP);
470 TcpClient tcpClient = new TcpClient();
471 tcpClient.Connect(session.RemoteEP);
472 //Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
473 //IPEndPoint localEP = new IPEndPoint(_IPEndPoint.Address, 0);
474 //s.Bind(localEP);
475 //s.Connect(session.RemoteEP);
476 //s.Send(datas);
477
478 Console.WriteLine("Connected, Sending data");
479 NetworkStream ns = tcpClient.GetStream();
480 ns.Write(datas, 0, datas.Length);
481 Console.WriteLine("Sended.");
482 //s.Close();
483 ns.Close();
484 tcpClient.Close();
485 }
486 catch (SocketException se)
487 {
488 Console.WriteLine(se.Message);
489 return false;
490 }
491 return true;
492 }
493
494 private bool SendOverPassiveDataConnection(byte[] datas, SessionInfo session)
495 {
496 try
497 {
498 Console.WriteLine("Connecting Client: {0}", session.RemoteEP);
499 TcpClient tcpClient = session.PassiveInfo.TcpListener.AcceptTcpClient();
500
501 Console.WriteLine("Connected, Sending data");
502 NetworkStream ns = tcpClient.GetStream();
503 ns.Write(datas, 0, datas.Length);
504 //int d=ns.DataAvailable
505 Thread.Sleep(100); //防止发送太快,客户端接收错误
506 Console.WriteLine("Sended.");
507 //s.Close();
508 ns.Close();
509 tcpClient.Close();
510 }
511 catch (SocketException se)
512 {
513 Console.WriteLine(se.Message);
514 return false;
515 }
516 return true;
517 }
518
519 /**//// <summary>
520 /// 用户指定端口,用于主动传输模式。每次传输前,用户都会设置端口
521 /// </summary>
522 /// <param name="socket"></param>
523 /// <param name="parameter"></param>
524 private void ProcessPortCommand(Socket socket, string parameter, SessionInfo session)
525 {
526 string[] endPoints = parameter.Split(',');
527 string remoteIP = endPoints[0] + "." + endPoints[1] + "."
528 + endPoints[2] + "." + endPoints[3];
529 //int port = Convert.ToInt32(endPoints[4] + endPoints[5]);
530 //endp[4] X 256 + endp[5];
531 int port = (Convert.ToInt32(endPoints[4]) * 256) + (int.Parse(endPoints[5]));
532 IPAddress ip = IPAddress.Parse(remoteIP);
533 IPEndPoint remoteEP = new IPEndPoint(ip, port);
534
535 session.RemoteEP = remoteEP;
536 Reply(socket, 200, "PORT Command successful.");
537 Console.WriteLine("PORT SET");
538 }
539
540 //响应被动模式命令
541 private void ProcessPassiveCommand(Socket socket, string parameter, SessionInfo session)
542 {
543 //创建一个空闲EP
544 IPEndPoint hostEP = new IPEndPoint(_IPHostEntry.AddressList[0], 0);
545 TcpListener tcpListener = new TcpListener(hostEP);
546 session.PassiveInfo.IPHostEntry = _IPHostEntry;
547 session.PassiveInfo.TcpListener = tcpListener;
548 //session.PassiveInfo.RemoteEP = hostEP;
549 session.Passive = true;
550 session.PassiveInfo.TcpListener.Start();
551
552 IPEndPoint localEP = (IPEndPoint)tcpListener.LocalEndpoint;
553 string ip = localEP.Address.ToString().Replace(".", ",");
554 int p1 = localEP.Port / 256;
555 int p2 = localEP.Port % 256;
556
557 Reply(socket, 227, "Entering Passive Mode (" + ip + "," + p1 + "," + p2 + ")");
558
559 }
560
561 private void AuthenticateUser(Socket socket, string username, string password)
562 {
563 //do Authenticate user name and password
564 Reply(socket, 230, "User logged in, proceed.");
565 }
566 }
567
568
569}
570
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.IO;
5using System.Net;
6using System.Net.Sockets;
7using System.Threading;
8using System.Globalization;
9
10namespace FtpServer
11{
12 public class Ftp
13 {
14 private TcpListener _tcpListener;
15 private Socket _socket;
16 private IPHostEntry _IPHostEntry;
17 private IPEndPoint _IPEndPoint;
18
19 public Ftp()
20 {
21 _IPHostEntry = Dns.GetHostEntry(Dns.GetHostName());
22 _IPEndPoint = new IPEndPoint(_IPHostEntry.AddressList[0], 21);
23 _tcpListener = new TcpListener(_IPEndPoint);
24 }
25
26 public bool Start()
27 {
28 try
29 {
30 _tcpListener.Start();
31 while (true)
32 {
33 //接收到客户端的一个连接请求,返回一个Socket响应它,采用多线程方式,支持多用户同时访问
34 //此Socket是处理用户的控制连接
35 _socket = _tcpListener.AcceptSocket();
36 Thread client = new Thread(new ThreadStart(ServerConnection));
37 client.Start();
38 }
39 }
40 catch (SocketException se)
41 {
42 Console.WriteLine("Error: {0}", se.Message);
43 return false;
44 }
45 }
46
47 public void Reply(Socket socket, int responseCode, string message)
48 {
49 try
50 {
51 string response = responseCode + " " + message + "\r\n";
52 byte[] datas = GetBytes(response);
53 socket.Send(datas);
54 }
55 catch (Exception e)
56 {
57 Console.WriteLine(e.Message);
58 }
59 }
60
61 private byte[] GetBytes(string response)
62 {
63 return GetBytes(response, Encoding.Default);
64 }
65
66 private byte[] GetBytes(string response, Encoding encoder)
67 {
68 return encoder.GetBytes(response);
69 }
70
71 private string GetString(byte[] datas, int offset, int size)
72 {
73 return GetString(datas, offset, size, Encoding.Default);
74 }
75
76 private string GetString(byte[] datas, int offset, int size, Encoding encoder)
77 {
78 return encoder.GetString(datas, offset, size);
79 }
80
81 /**//// <summary>
82 /// 处理一个连接请求
83 /// </summary>
84 private void ServerConnection()
85 {
86 //这里需要互斥访问??
87 Socket socket = _socket;
88 //建立一个新会话
89 SessionInfo session = new SessionInfo();
90 session.RemoteEP = (IPEndPoint)socket.RemoteEndPoint;
91 //显示服务器信息
92 string message = "Welcome to MK FTP Server v1.0, Base on .NET Framework 2.0.";
93 Reply(socket, 220, message);
94
95 //分析用户命令
96 CheckCommand(socket, session);
97 }
98
99 private void CheckCommand(Socket socket, SessionInfo session)
100 {
101 try
102 {
103 //循环执行用户命令
104 while (true)
105 {
106 byte[] buffer = new byte[256];
107 //接收命令
108 int dataSize = socket.Receive(buffer);
109 string cmd = GetString(buffer, 0, dataSize).Replace("\r\n", "");
110 string command = "";
111 string parameter = "";
112 if (cmd.Length == 3)
113 command = cmd;
114 else
115 command = cmd.Substring(0, 3);
116 string paras = "";
117 command = command.ToUpper();
118 if (command != "CWD" && command != "PWD")
119 {
120 command = cmd.Substring(0, 4).ToUpper();
121 if (cmd.Length > 4)
122 parameter = cmd.Substring(5);
123 }
124 else
125 {
126 if (cmd.Length > 3)
127 {
128 parameter = cmd.Substring(4);
129 }
130 }
131 //for (int i = 0; i < 4; i++)
132 //{
133 // //不是回车换行符
134 // if (buffer[i] != 0 && buffer[i] != 13 && buffer[i] != 10 && buffer[i] != 32)
135 // {
136 // command += (char)buffer[i];
137 // }
138 //}
139 //if (command != "CWD" && command != "PWD")
140 //{
141 // for (int i = 5; i < buffer.Length; i++)
142 // {
143 // //不是回车换行符
144 // if (buffer[i] != 0 && buffer[i] != 13 && buffer[i] != 10 && buffer[i] != 32)
145 // {
146 // parameter += (char)buffer[i];
147 // }
148 // }
149 //}
150 //else
151 //{
152 // for (int i = 4; i < buffer.Length; i++)
153 // {
154 // //不是回车换行符
155 // if (buffer[i] != 0 && buffer[i] != 13 && buffer[i] != 10 && buffer[i] != 32)
156 // {
157 // parameter += (char)buffer[i];
158 // }
159 // }
160 //}
161 //parameter = parameter.Trim();
162 System.Console.WriteLine("From {0} : {1} {2}", socket.RemoteEndPoint, command, parameter);
163
164 //FTP命令格式:前4位为命令类型,后面为命令参数
165 switch (command)
166 {
167 //用户
168 case "USER":
169 session.UserName = parameter;
170 Reply(socket, 331, "User name okey, need password.");
171 break;
172 //密码
173 case "PASS":
174 session.Password = parameter;
175 AuthenticateUser(socket, session.UserName, session.Password);
176 break;
177 //EPSV 扩展被动模式
178 case "EPSV":
179 Reply(socket, 522, "Extended Passive Mode not supported.");
180 break;
181 //被动模式
182 case "PASV":
183 session.Passive = true;
184 ProcessPassiveCommand(socket, parameter, session);
185 break;
186 //设定主动模式的数据连接端口
187 case "PORT":
188 session.Passive = false;
189 ProcessPortCommand(socket, parameter, session);
190 break;
191 //文件及子目录列表
192 case "LIST":
193 ProcessListCommand(socket, parameter, session);
194 break;
195 //发送客户端下载的文件
196 case "RETR":
197 ProcessRetreiveCommand(socket, parameter, session);
198 break;
199 //名字系统类型
200 case "SYST":
201 Reply(socket, 215, System.Environment.OSVersion.VersionString);
202 break;
203 //上传文件
204 case "STOR":
205 ProcessStoreCommand(socket, parameter, session);
206 break;
207 //改变工作目录
208 case "CWD":
209 ProcessCWDCommand(socket, parameter, session);
210 break;
211 //当前目录
212 case "PWD":
213 ProcessPWDCommand(socket, parameter, session);
214 break;
215 //传输模式
216 case "TYPE":
217 switch (parameter)
218 {
219 case "I":
220 session.Binary = true;
221 Reply(socket, 200, "Type set to I.");
222 break;
223 case "A":
224 session.Binary = false;
225 Reply(socket, 200, "Type set to A.");
226 break;
227 default:
228 Reply(socket, 200, "Type not change.");
229 break;
230 }
231 break;
232 //退出
233 case "QUIT":
234 Reply(socket, 221, "Goodbye!.");
235 socket.Close();
236 return;
237 default:
238 Reply(socket, 502, "'" + command + "': not implemented.");
239 break;
240 }
241 }
242 }
243 catch (Exception e)
244 {
245 Console.WriteLine(e.Message);
246 }
247 }
248
249 private void ProcessPWDCommand(Socket socket, string parameter, SessionInfo session)
250 {
251 Reply(socket, 257, "\"" + session.FtpRoot + "\" is current directory.");
252 }
253
254 private void ProcessCWDCommand(Socket socket, string parameter, SessionInfo session)
255 {
256 if (parameter.IndexOf("\\") > 0 && parameter.IndexOf(":") > 0)
257 {
258 session.FtpRoot = parameter;
259 }
260 else
261 {
262 session.FtpRoot += @"\" + parameter;
263 }
264
265 DirectoryInfo dir = new DirectoryInfo(session.FtpRoot);
266 if (!dir.Exists)
267 {
268 Reply(socket, 550, dir.FullName + ": No such directory.");
269 return;
270 }
271 Reply(socket, 250, "Directory changed to "+dir.FullName);
272 }
273
274 private void ProcessStoreCommand(Socket socket, string parameter, SessionInfo session)
275 {
276 try
277 {
278 string file = session.FtpRoot + @"\" + parameter;
279 FileStream fs = new FileStream(file, FileMode.Create);
280
281 byte[] buffer = new byte[1024];
282
283 int dataSize = 0;
284
285 if (session.Binary)
286 {
287 Reply(socket, 150, "Opening BINARY mode data connection for " + parameter);
288 BinaryWriter bw = new BinaryWriter(fs);
289 Socket binarySocket;
290 if (session.Passive)
291 {
292 binarySocket = session.PassiveInfo.TcpListener.AcceptSocket();
293
294 }
295 else
296 {
297 binarySocket = new Socket(AddressFamily.InterNetwork,
298 SocketType.Stream, ProtocolType.Tcp);
299 binarySocket.Bind(new IPEndPoint(_IPEndPoint.Address, 0));
300 binarySocket.Connect(session.RemoteEP);
301 }
302 while ((dataSize = binarySocket.Receive(buffer)) > 0)
303 {
304 bw.Write(buffer, 0, dataSize);
305 }
306 bw.Close();
307 binarySocket.Close();
308 }
309 else
310 {
311 //FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open);
312 //Reply(socket, 150, "Opening ASCII mode data connection for " + parameter
313 // + " (" + fileInfo.Length + " Bytes).");
314 //StreamReader sr = new StreamReader(fs);
315 //if (session.Passive)
316 //{
317 // SendOverPassiveDataConnection(GetBytes(sr.ReadToEnd(), Encoding.UTF8), session);
318
319 //}
320 //else
321 //{
322 // SendOverDataConnection(GetBytes(sr.ReadToEnd(), Encoding.UTF8), session);
323 //}
324 //sr.Close();
325 //fs.Close();
326 }
327
328 Reply(socket, 226, "Transfer Complete");
329
330 }
331 catch (Exception e)
332 {
333 Console.WriteLine(e.Message);
334 }
335 }
336
337 private void ProcessRetreiveCommand(Socket socket, string parameter, SessionInfo session)
338 {
339 try
340 {
341 string file = session.FtpRoot + @"\" + parameter;
342 FileInfo fileInfo =new FileInfo(file);
343 if (!fileInfo.Exists)
344 {
345 Reply(socket, 550, fileInfo.FullName + ": No such file.");
346 return;
347 }
348 if (session.Binary)
349 {
350 Reply(socket, 150, "Opening BINARY mode data connection for " + parameter
351 + " (" + fileInfo.Length + " Bytes)");
352 //BinaryReader br = new BinaryReader(fs);
353 Socket binarySocket;
354 if (session.Passive)
355 {
356 binarySocket = session.PassiveInfo.TcpListener.AcceptSocket();
357 }
358 else
359 {
360 binarySocket = new Socket(AddressFamily.InterNetwork,
361 SocketType.Stream, ProtocolType.Tcp);
362 binarySocket.Bind(new IPEndPoint(_IPEndPoint.Address, 0));
363 binarySocket.Connect(session.RemoteEP);
364 }
365 //while (br.PeekChar() > -1)
366 //{
367 // binarySocket.Send(br.ReadBytes(10240));
368 // //binarySocket.
369 //}
370 //br.Close();
371 binarySocket.SendFile(fileInfo.FullName);
372 binarySocket.Close();
373 }
374 else
375 {
376 FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open);
377 Reply(socket, 150, "Opening ASCII mode data connection for " + parameter
378 + " (" + fileInfo.Length + " Bytes).");
379 StreamReader sr = new StreamReader(fs);
380 if (session.Passive)
381 {
382 SendOverPassiveDataConnection(GetBytes(sr.ReadToEnd()), session);
383
384 }
385 else
386 {
387 SendOverDataConnection(GetBytes(sr.ReadToEnd()), session);
388 }
389 sr.Close();
390 fs.Close();
391 }
392
393 Reply(socket, 200, "Transfer Complete");
394
395 }
396 catch (Exception e)
397 {
398 Console.WriteLine(e.Message);
399 }
400 }
401
402 private void ProcessListCommand(Socket socket, string parameter, SessionInfo session)
403 {
404 DirectoryInfo curDir = new DirectoryInfo(session.FtpRoot);
405 DirectoryInfo[] dirInfoList = curDir.GetDirectories();
406 FileInfo[] fileSysInfoList = curDir.GetFiles();
407
408 const string s_dir = "\t";//"┼ <DIR> ";
409 const string s_file = "";// "├ ";
410 const string s_d_right = "drw-rw-rw-";
411 const string s_f_right = "_rw-rw-rw-";
412 const string s_1 = " ";
413 const string s_3 = " ";
414 const string s_7 = " ";
415 const string s_10 = " ";
416 StringBuilder sb = new StringBuilder();
417 foreach (DirectoryInfo dir in dirInfoList)
418 {
419 //sb.Append(s_d_right + s_1 + "1 user" + s_1 + "group" + s_1 + 0 + s_1 + dir.LastWriteTime + s_1 + dir.Name);
420 //sb.Append("\r\n");
421 GetFormatRow(sb, s_d_right, 0, dir.LastWriteTime, dir.Name);
422 }
423
424 foreach (FileInfo file in fileSysInfoList)
425 {
426 //sb.Append(s_f_right + s_1 + "1 user" + s_1 + "group" + s_1 + file.Length + s_1 + file.LastWriteTime + s_1 + file.Name);
427 //sb.Append("\r\n");
428 GetFormatRow(sb, s_f_right, file.Length, file.LastWriteTime, file.Name);
429 }
430
431 Reply(socket, 150, "Opening ASCII mode data connection for /bin/ls.");
432 if (session.Passive)
433 {
434 SendOverPassiveDataConnection(GetBytes(sb.ToString()), session);
435 }
436 else
437 {
438 SendOverDataConnection(GetBytes(sb.ToString()), session);
439 }
440 Console.WriteLine("Listed.");
441 //socket.
442 Reply(socket, 226, "Transfer complete.");
443
444 }
445
446 private string GetFormatRow(StringBuilder sb, string right, Int64 size, DateTime date, string name)
447 {
448 const string s_1 = " ";
449 sb.Append(right + s_1);
450 sb.Append("user group ");
451 for (int i = size.ToString().Length; i < 12; i++)
452 {
453 sb.Append(s_1);
454 }
455 sb.Append(size + s_1);
456 sb.Append(date.ToString("MMM d hh:ss ", DateTimeFormatInfo.InvariantInfo));
457 sb.Append(name + "\r\n");
458 return sb.ToString();
459 }
460
461 /**//// <summary>
462 /// 主动模式下传输数据
463 /// </summary>
464 /// <param name="p"></param>
465 private bool SendOverDataConnection(byte[] datas, SessionInfo session)
466 {
467 try
468 {
469 Console.WriteLine("Connecting Client: {0}", session.RemoteEP);
470 TcpClient tcpClient = new TcpClient();
471 tcpClient.Connect(session.RemoteEP);
472 //Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
473 //IPEndPoint localEP = new IPEndPoint(_IPEndPoint.Address, 0);
474 //s.Bind(localEP);
475 //s.Connect(session.RemoteEP);
476 //s.Send(datas);
477
478 Console.WriteLine("Connected, Sending data");
479 NetworkStream ns = tcpClient.GetStream();
480 ns.Write(datas, 0, datas.Length);
481 Console.WriteLine("Sended.");
482 //s.Close();
483 ns.Close();
484 tcpClient.Close();
485 }
486 catch (SocketException se)
487 {
488 Console.WriteLine(se.Message);
489 return false;
490 }
491 return true;
492 }
493
494 private bool SendOverPassiveDataConnection(byte[] datas, SessionInfo session)
495 {
496 try
497 {
498 Console.WriteLine("Connecting Client: {0}", session.RemoteEP);
499 TcpClient tcpClient = session.PassiveInfo.TcpListener.AcceptTcpClient();
500
501 Console.WriteLine("Connected, Sending data");
502 NetworkStream ns = tcpClient.GetStream();
503 ns.Write(datas, 0, datas.Length);
504 //int d=ns.DataAvailable
505 Thread.Sleep(100); //防止发送太快,客户端接收错误
506 Console.WriteLine("Sended.");
507 //s.Close();
508 ns.Close();
509 tcpClient.Close();
510 }
511 catch (SocketException se)
512 {
513 Console.WriteLine(se.Message);
514 return false;
515 }
516 return true;
517 }
518
519 /**//// <summary>
520 /// 用户指定端口,用于主动传输模式。每次传输前,用户都会设置端口
521 /// </summary>
522 /// <param name="socket"></param>
523 /// <param name="parameter"></param>
524 private void ProcessPortCommand(Socket socket, string parameter, SessionInfo session)
525 {
526 string[] endPoints = parameter.Split(',');
527 string remoteIP = endPoints[0] + "." + endPoints[1] + "."
528 + endPoints[2] + "." + endPoints[3];
529 //int port = Convert.ToInt32(endPoints[4] + endPoints[5]);
530 //endp[4] X 256 + endp[5];
531 int port = (Convert.ToInt32(endPoints[4]) * 256) + (int.Parse(endPoints[5]));
532 IPAddress ip = IPAddress.Parse(remoteIP);
533 IPEndPoint remoteEP = new IPEndPoint(ip, port);
534
535 session.RemoteEP = remoteEP;
536 Reply(socket, 200, "PORT Command successful.");
537 Console.WriteLine("PORT SET");
538 }
539
540 //响应被动模式命令
541 private void ProcessPassiveCommand(Socket socket, string parameter, SessionInfo session)
542 {
543 //创建一个空闲EP
544 IPEndPoint hostEP = new IPEndPoint(_IPHostEntry.AddressList[0], 0);
545 TcpListener tcpListener = new TcpListener(hostEP);
546 session.PassiveInfo.IPHostEntry = _IPHostEntry;
547 session.PassiveInfo.TcpListener = tcpListener;
548 //session.PassiveInfo.RemoteEP = hostEP;
549 session.Passive = true;
550 session.PassiveInfo.TcpListener.Start();
551
552 IPEndPoint localEP = (IPEndPoint)tcpListener.LocalEndpoint;
553 string ip = localEP.Address.ToString().Replace(".", ",");
554 int p1 = localEP.Port / 256;
555 int p2 = localEP.Port % 256;
556
557 Reply(socket, 227, "Entering Passive Mode (" + ip + "," + p1 + "," + p2 + ")");
558
559 }
560
561 private void AuthenticateUser(Socket socket, string username, string password)
562 {
563 //do Authenticate user name and password
564 Reply(socket, 230, "User logged in, proceed.");
565 }
566 }
567
568
569}
570
FtpClient.ClientMainApp
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.IO;
5using System.Net;
6using System.Net.Sockets;
7using System.Threading;
8using System.Globalization;
9
10namespace FtpClient
11{
12 class ClientMainApp
13 {
14 static void Main(string[] args)
15 {
16 try
17 {
18 IPHostEntry server;
19 try
20 {
21 server = Dns.GetHostEntry(IPAddress.Parse(args[0]));
22 }
23 catch
24 {
25 server = Dns.GetHostEntry(args[0]);
26 }
27
28
29
30 IPEndPoint serverEP = new IPEndPoint(server.AddressList[0], 21);
31
32 FtpViewer browser = new FtpViewer(serverEP);
33 browser.Start();
34
35 /**/////登录FTP Server
36 //Console.WriteLine("USER anonymous");
37 //browser.Excute("USER anonymous");
38 //Console.WriteLine("PASS 1111");
39 //browser.Excute("PASS 1111");
40 //Console.WriteLine("SYST");
41 //browser.Excute("SYST");
42 //Console.WriteLine("PWD");
43 //browser.Excute("PWD");
44 //Console.WriteLine("TYPE A");
45 //browser.Excute("TYPE A");
46 //Console.WriteLine("PORT");
47 //browser.Excute("PORT");
48 //Console.WriteLine("LIST");
49 //browser.Excute("LIST");
50 //browser.ExcuteCommand("dir");
51
52
53
54 /**///////下载文件
55 ////Console.WriteLine("TYPE I");
56 ////browser.Excute("TYPE I");
57 ////Console.WriteLine("PASV");
58 ////browser.Excute("PASV");
59 ////Console.WriteLine("RETR picture.JPG");
60 ////browser.Excute("RETR picture.JPG");
61 //browser.ExcuteCommand("get picture.JPG");
62
63 /**///////更改目录
64 ////Console.WriteLine("CWD files");
65 ////browser.Excute("CWD files");
66 ////Console.WriteLine("PWD");
67 ////browser.Excute("PWD");
68 ////Console.WriteLine("PASV");
69 ////browser.Excute("PASV");
70 ////Console.WriteLine("LIST -al");
71 ////browser.Excute("LIST -al");
72 //browser.ExcuteCommand("cd files");
73
74 /**///////上传文件
75 ////Console.WriteLine("TYPE I");
76 ////browser.Excute("TYPE I");
77 ////Console.WriteLine("PASV");
78 ////browser.Excute("PASV");
79 ////Console.WriteLine("STOR network4.rar");
80 ////browser.Excute("STOR network4.rar");
81 //browser.ExcuteCommand("put network4.rar");
82
83 /**/////Console.WriteLine("RETR testFiles222.txt");
84 ////browser.Excute("RETR testFiles222.txt");
85 ////Console.WriteLine("RETR testFiles1.txt");
86 ////browser.Excute("RETR testFiles1.txt");
87 ////Console.WriteLine("RETR picture.JPG");
88 ////browser.Excute("RETR picture.JPG");
89 ////Console.WriteLine("RETR network4.rar");
90 ////browser.Excute("RETR network4.rar");
91 ////Console.WriteLine("R2TR sdlfjldjgsd");
92 ////browser.Excute("R2TR sdlfjldjgsd");
93 ////Console.WriteLine("CWD files");
94 ////browser.Excute("CWD files");
95 ////Console.WriteLine("RETR files_ftp应答码.txt");
96 ////browser.Excute("RETR files_ftp应答码.txt");
97
98 ////browser.ExcuteCommand("quit");
99 //browser.ExcuteCommand("user anonymous 123");
100 while (browser.IsRunning)
101 {
102 Console.Write("ftp> ");
103 string cmd = Console.ReadLine();
104 browser.ExcuteCommand(cmd);
105 }
106 }
107 catch (Exception e)
108 {
109 Console.WriteLine(e.Message);
110 }
111 //Console.Read();
112 }
113
114
115 }
116}
117
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.IO;
5using System.Net;
6using System.Net.Sockets;
7using System.Threading;
8using System.Globalization;
9
10namespace FtpClient
11{
12 class ClientMainApp
13 {
14 static void Main(string[] args)
15 {
16 try
17 {
18 IPHostEntry server;
19 try
20 {
21 server = Dns.GetHostEntry(IPAddress.Parse(args[0]));
22 }
23 catch
24 {
25 server = Dns.GetHostEntry(args[0]);
26 }
27
28
29
30 IPEndPoint serverEP = new IPEndPoint(server.AddressList[0], 21);
31
32 FtpViewer browser = new FtpViewer(serverEP);
33 browser.Start();
34
35 /**/////登录FTP Server
36 //Console.WriteLine("USER anonymous");
37 //browser.Excute("USER anonymous");
38 //Console.WriteLine("PASS 1111");
39 //browser.Excute("PASS 1111");
40 //Console.WriteLine("SYST");
41 //browser.Excute("SYST");
42 //Console.WriteLine("PWD");
43 //browser.Excute("PWD");
44 //Console.WriteLine("TYPE A");
45 //browser.Excute("TYPE A");
46 //Console.WriteLine("PORT");
47 //browser.Excute("PORT");
48 //Console.WriteLine("LIST");
49 //browser.Excute("LIST");
50 //browser.ExcuteCommand("dir");
51
52
53
54 /**///////下载文件
55 ////Console.WriteLine("TYPE I");
56 ////browser.Excute("TYPE I");
57 ////Console.WriteLine("PASV");
58 ////browser.Excute("PASV");
59 ////Console.WriteLine("RETR picture.JPG");
60 ////browser.Excute("RETR picture.JPG");
61 //browser.ExcuteCommand("get picture.JPG");
62
63 /**///////更改目录
64 ////Console.WriteLine("CWD files");
65 ////browser.Excute("CWD files");
66 ////Console.WriteLine("PWD");
67 ////browser.Excute("PWD");
68 ////Console.WriteLine("PASV");
69 ////browser.Excute("PASV");
70 ////Console.WriteLine("LIST -al");
71 ////browser.Excute("LIST -al");
72 //browser.ExcuteCommand("cd files");
73
74 /**///////上传文件
75 ////Console.WriteLine("TYPE I");
76 ////browser.Excute("TYPE I");
77 ////Console.WriteLine("PASV");
78 ////browser.Excute("PASV");
79 ////Console.WriteLine("STOR network4.rar");
80 ////browser.Excute("STOR network4.rar");
81 //browser.ExcuteCommand("put network4.rar");
82
83 /**/////Console.WriteLine("RETR testFiles222.txt");
84 ////browser.Excute("RETR testFiles222.txt");
85 ////Console.WriteLine("RETR testFiles1.txt");
86 ////browser.Excute("RETR testFiles1.txt");
87 ////Console.WriteLine("RETR picture.JPG");
88 ////browser.Excute("RETR picture.JPG");
89 ////Console.WriteLine("RETR network4.rar");
90 ////browser.Excute("RETR network4.rar");
91 ////Console.WriteLine("R2TR sdlfjldjgsd");
92 ////browser.Excute("R2TR sdlfjldjgsd");
93 ////Console.WriteLine("CWD files");
94 ////browser.Excute("CWD files");
95 ////Console.WriteLine("RETR files_ftp应答码.txt");
96 ////browser.Excute("RETR files_ftp应答码.txt");
97
98 ////browser.ExcuteCommand("quit");
99 //browser.ExcuteCommand("user anonymous 123");
100 while (browser.IsRunning)
101 {
102 Console.Write("ftp> ");
103 string cmd = Console.ReadLine();
104 browser.ExcuteCommand(cmd);
105 }
106 }
107 catch (Exception e)
108 {
109 Console.WriteLine(e.Message);
110 }
111 //Console.Read();
112 }
113
114
115 }
116}
117
FtpClient.ControlInfo
1using System;
2using System.Collections.Generic;
3using System.Text;
4
5namespace FtpClient
6{
7 public class ControlInfo
8 {
9 private string _sendCommand;
10
11 public string SendCommand
12 {
13 get { return _sendCommand; }
14 set { _sendCommand = value; }
15 }
16
17 private string _command;
18
19 public string Command
20 {
21 get { return _command; }
22 set { _command = value; }
23 }
24 private string _parameter;
25
26 public string Parameter
27 {
28 get { return _parameter; }
29 set { _parameter = value; }
30 }
31
32 private string _parameter2 = "";
33
34 public string Parameter2
35 {
36 get { return _parameter2; }
37 set { _parameter2 = value; }
38 }
39
40 private int _successCode;
41
42 public int SuccessCode
43 {
44 get { return _successCode; }
45 set { _successCode = value; }
46 }
47 private int _returnCode;
48
49 public int ReturnCode
50 {
51 get { return _returnCode; }
52 set { _returnCode = value; }
53 }
54 private string _message;
55
56 public string Message
57 {
58 get { return _message; }
59 set { _message = value; }
60 }
61
62 private string _returnResult;
63
64 public string ReturnResult
65 {
66 get { return _returnResult; }
67 set { _returnResult = value; }
68 }
69
70 public ControlInfo()
71 {
72 _successCode = 220;
73 }
74
75 public ControlInfo(string cmd, string paras)
76 {
77 _command = cmd;
78 _parameter = paras;
79 _successCode = GetSuccessCode(cmd);
80 }
81
82 public ControlInfo(string sendCommand, string cmd, string paras)
83 {
84 _sendCommand = sendCommand;
85 _command = cmd;
86 _parameter = paras;
87 _successCode = GetSuccessCode(cmd);
88 }
89
90 public ControlInfo(string sendCommand, string cmd, string paras, string paras2)
91 {
92 _sendCommand = sendCommand;
93 _command = cmd;
94 _parameter = paras;
95 _parameter2 = paras2;
96 _successCode = GetSuccessCode(cmd);
97 }
98
99 //指示此初操作命令是否成功
100 public bool Success
101 {
102 get
103 {
104 return _returnCode == _successCode;
105 }
106 }
107
108 /**//// <summary>
109 /// 获取带参数的命令
110 /// </summary>
111 /// <returns></returns>
112 public string GetCommand()
113 {
114 return _command + (_parameter.Length > 0 ? " " + _parameter : "") + "\r\n";
115 }
116
117 /**//// <summary>
118 /// 获取指定命令成功执行希望得到响应的代码
119 /// </summary>
120 /// <param name="command"></param>
121 /// <returns></returns>
122 public static int GetSuccessCode(string command)
123 {
124 switch (command)
125 {
126 //用户
127 case "USER":
128 return 331;
129 //密码
130 case "PASS":
131 return 230;
132 //EPSV
133 case "EPSV":
134 return 522;
135 //被动模式
136 case "PASV":
137 return 227;
138 //设定主动模式的数据连接端口
139 case "PORT":
140 return 200;
141 //文件及子目录列表
142 case "LIST":
143 return 150;
144 //发送客户端下载的文件
145 case "RETR":
146 return 150;
147 //名字系统类型
148 case "SYST":
149 return 215;
150 //上传文件
151 case "STOR":
152 return 150;
153 //改变工作目录
154 case "CWD":
155 return 250;
156 //当前目录
157 case "PWD":
158 return 257;
159 //传输模式
160 case "TYPE":
161 return 200;
162 default:
163 return 0;
164 }
165 }
166
167 public static ControlInfo Create(string command)
168 {
169 string cmd = "";
170 if (command.Length == 3)
171 cmd = command;
172 else
173 cmd = command.Substring(0, 3);
174 string paras = "";
175 cmd = cmd.ToUpper();
176 if (cmd != "CWD" && cmd != "PWD")
177 {
178 cmd = command.Substring(0, 4).ToUpper();
179 if (command.Length > 4)
180 paras = command.Substring(5);
181 }
182 else
183 {
184 if (command.Length > 3)
185 {
186 paras = command.Substring(4);
187 }
188 }
189 if (paras.IndexOf(" ") > 0)
190 {
191 int index = paras.IndexOf(" ");
192 string paras2 = paras.Substring(index + 1);
193 paras = paras.Substring(0, index);
194 ControlInfo cInfo2 = new ControlInfo(command, cmd, paras, paras2);
195 return cInfo2;
196 }
197 ControlInfo cInfo = new ControlInfo(command, cmd, paras);
198 return cInfo;
199 }
200 }
201}
202
1using System;
2using System.Collections.Generic;
3using System.Text;
4
5namespace FtpClient
6{
7 public class ControlInfo
8 {
9 private string _sendCommand;
10
11 public string SendCommand
12 {
13 get { return _sendCommand; }
14 set { _sendCommand = value; }
15 }
16
17 private string _command;
18
19 public string Command
20 {
21 get { return _command; }
22 set { _command = value; }
23 }
24 private string _parameter;
25
26 public string Parameter
27 {
28 get { return _parameter; }
29 set { _parameter = value; }
30 }
31
32 private string _parameter2 = "";
33
34 public string Parameter2
35 {
36 get { return _parameter2; }
37 set { _parameter2 = value; }
38 }
39
40 private int _successCode;
41
42 public int SuccessCode
43 {
44 get { return _successCode; }
45 set { _successCode = value; }
46 }
47 private int _returnCode;
48
49 public int ReturnCode
50 {
51 get { return _returnCode; }
52 set { _returnCode = value; }
53 }
54 private string _message;
55
56 public string Message
57 {
58 get { return _message; }
59 set { _message = value; }
60 }
61
62 private string _returnResult;
63
64 public string ReturnResult
65 {
66 get { return _returnResult; }
67 set { _returnResult = value; }
68 }
69
70 public ControlInfo()
71 {
72 _successCode = 220;
73 }
74
75 public ControlInfo(string cmd, string paras)
76 {
77 _command = cmd;
78 _parameter = paras;
79 _successCode = GetSuccessCode(cmd);
80 }
81
82 public ControlInfo(string sendCommand, string cmd, string paras)
83 {
84 _sendCommand = sendCommand;
85 _command = cmd;
86 _parameter = paras;
87 _successCode = GetSuccessCode(cmd);
88 }
89
90 public ControlInfo(string sendCommand, string cmd, string paras, string paras2)
91 {
92 _sendCommand = sendCommand;
93 _command = cmd;
94 _parameter = paras;
95 _parameter2 = paras2;
96 _successCode = GetSuccessCode(cmd);
97 }
98
99 //指示此初操作命令是否成功
100 public bool Success
101 {
102 get
103 {
104 return _returnCode == _successCode;
105 }
106 }
107
108 /**//// <summary>
109 /// 获取带参数的命令
110 /// </summary>
111 /// <returns></returns>
112 public string GetCommand()
113 {
114 return _command + (_parameter.Length > 0 ? " " + _parameter : "") + "\r\n";
115 }
116
117 /**//// <summary>
118 /// 获取指定命令成功执行希望得到响应的代码
119 /// </summary>
120 /// <param name="command"></param>
121 /// <returns></returns>
122 public static int GetSuccessCode(string command)
123 {
124 switch (command)
125 {
126 //用户
127 case "USER":
128 return 331;
129 //密码
130 case "PASS":
131 return 230;
132 //EPSV
133 case "EPSV":
134 return 522;
135 //被动模式
136 case "PASV":
137 return 227;
138 //设定主动模式的数据连接端口
139 case "PORT":
140 return 200;
141 //文件及子目录列表
142 case "LIST":
143 return 150;
144 //发送客户端下载的文件
145 case "RETR":
146 return 150;
147 //名字系统类型
148 case "SYST":
149 return 215;
150 //上传文件
151 case "STOR":
152 return 150;
153 //改变工作目录
154 case "CWD":
155 return 250;
156 //当前目录
157 case "PWD":
158 return 257;
159 //传输模式
160 case "TYPE":
161 return 200;
162 default:
163 return 0;
164 }
165 }
166
167 public static ControlInfo Create(string command)
168 {
169 string cmd = "";
170 if (command.Length == 3)
171 cmd = command;
172 else
173 cmd = command.Substring(0, 3);
174 string paras = "";
175 cmd = cmd.ToUpper();
176 if (cmd != "CWD" && cmd != "PWD")
177 {
178 cmd = command.Substring(0, 4).ToUpper();
179 if (command.Length > 4)
180 paras = command.Substring(5);
181 }
182 else
183 {
184 if (command.Length > 3)
185 {
186 paras = command.Substring(4);
187 }
188 }
189 if (paras.IndexOf(" ") > 0)
190 {
191 int index = paras.IndexOf(" ");
192 string paras2 = paras.Substring(index + 1);
193 paras = paras.Substring(0, index);
194 ControlInfo cInfo2 = new ControlInfo(command, cmd, paras, paras2);
195 return cInfo2;
196 }
197 ControlInfo cInfo = new ControlInfo(command, cmd, paras);
198 return cInfo;
199 }
200 }
201}
202
FtpClient.FtpViewer
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.IO;
5using System.Net;
6using System.Net.Sockets;
7using System.Threading;
8using System.Globalization;
9using System.Collections;
10
11namespace FtpClient
12{
13 public class FtpViewer
14 {
15 private TcpClient _commandControler;
16 private TcpListener _listener;
17 private TcpClient _dataControler;
18 private IPEndPoint _serverEndPoint;
19 private IPEndPoint _transferEndPoint;
20 private IPAddress _clientIP;
21 private string _username;
22 private string _password;
23 private string _currentDir;
24 private string _serverDir = @"\";
25 private bool _isPassive = true; //默认被动模式,采用二进制模式传输数据
26 private bool _isBinary = true;
27 private bool _isRunning = false;
28
29 public bool IsRunning
30 {
31 get { return _isRunning; }
32 set { _isRunning = value; }
33 }
34
35 public FtpViewer()
36 {
37
38 }
39
40 public FtpViewer(IPEndPoint serverEndPoint)
41 {
42 _clientIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
43 _serverEndPoint = serverEndPoint;
44 _commandControler = new TcpClient();
45 _currentDir = System.Environment.CurrentDirectory;
46 }
47
48 public void SetBinaryMode(bool isBinary)
49 {
50 if (isBinary != _isBinary)
51 {
52 _isBinary = isBinary;
53 if (isBinary)
54 {
55 Excute("TYPE I");
56 }
57 else
58 {
59 Excute("TYPE A");
60 }
61 }
62 }
63
64 public bool Start()
65 {
66 _commandControler.Connect(_serverEndPoint);
67 ControlInfo controlInfo = new ControlInfo();
68 ReadReply(controlInfo);
69 Display(controlInfo.ReturnResult);
70
71 DisplayCommand("User (" + _serverEndPoint.ToString() + ":) ");
72 Login(Console.ReadLine());
73
74 _isRunning = true;
75 return true;
76 }
77
78 public void Close()
79 {
80 if (_commandControler != null)
81 {
82 _commandControler.Close();
83 _commandControler = null;
84 }
85 if (_dataControler != null)
86 {
87 _dataControler.Close();
88 _dataControler = null;
89 }
90 _isRunning = false;
91 }
92
93 public bool ReadReply(ControlInfo controlInfo)
94 {
95 try
96 {
97 NetworkStream ns = _commandControler.GetStream();
98
99 byte[] buffer = new byte[_commandControler.ReceiveBufferSize];
100 int dataSize = ns.Read(buffer, 0, buffer.Length);
101 string result = GetString(buffer, 0, dataSize);
102
103 if (result.Length == 0)
104 {
105 controlInfo.ReturnCode = 0;
106 controlInfo.Message = "";
107 controlInfo.ReturnResult = "";
108 return true;
109 }
110
111 controlInfo.ReturnCode = Convert.ToInt32(result.Substring(0, 3));
112 controlInfo.Message = result.Substring(4);
113 controlInfo.ReturnResult = result;
114
115 return true;
116 }
117 catch(Exception e)
118 {
119 controlInfo.ReturnCode = 0;
120 controlInfo.Message = "";
121 controlInfo.ReturnResult = "";
122 DisplayLocalMessage(e.Message);
123 return false;
124 }
125 }
126
127 public bool ReceiveData(ControlInfo controlInfo)
128 {
129 InitDataControler();
130
131 Send(controlInfo);
132 ReadReply(controlInfo);
133 Display(controlInfo.ReturnResult);
134
135 if (!controlInfo.Success)
136 {
137 Display( controlInfo.Parameter + " 传输失败!\n");
138 return false;
139 }
140 try
141 {
142
143 int startTime = Environment.TickCount;
144
145 NetworkStream ns = _dataControler.GetStream();
146 string filename = controlInfo.Parameter2.Length > 0 ? controlInfo.Parameter2 : controlInfo.Parameter;
147
148 FileStream fs = new FileStream(_currentDir + @"\" + filename, FileMode.Create);
149 Int64 totalSize = 0;
150 if (_isBinary)
151 {
152 byte[] buffer = new byte[1024];
153
154 int dataSize = 0;
155
156 BinaryWriter bw = new BinaryWriter(fs);
157
158 while ((dataSize = ns.Read(buffer, 0, buffer.Length)) > 0)
159 {
160 totalSize += dataSize;
161 bw.Write(buffer, 0, dataSize);
162 }
163
164 bw.Close();
165 }
166 else
167 {
168 //ArrayList datas = new ArrayList();
169 //StreamWriter sw
170 //while ((dataSize = ns.Read(buffer, 0, buffer.Length)) > 0)
171 //{
172 // //sw.Write(Encoding.UTF8.GetChars(buffer, 0, dataSize),
173 // //0, dataSize);
174 //}
175
176 //StreamWriter sw = new StreamWriter(fs);
177 //sw.Write(Encoding.UTF8.GetString(buffer, 0, dataSize));
178 //Display("已传送 " + controlInfo.Parameter + " " + fs.Length + " bytes. \n");
179 //sw.Close();
180 }
181
182 fs.Close();
183 ns.Close();
184 _dataControler.Close();
185 ReadReply(controlInfo);
186 Display(controlInfo.ReturnResult);
187 double useTime = GetUseTime(startTime, Environment.TickCount);
188 double speed = totalSize / useTime;
189
190 Display("已传送 " + filename + " " + totalSize + " bytes, use time " +
191 useTime.ToString("f2") + " Seconds (" + GetSpeed(speed) + ").\n");
192
193 return true;
194 }
195 catch (Exception e)
196 {
197 DisplayLocalMessage(e.Message);
198 return false;
199 }
200 }
201
202 private void InitDataControler()
203 {
204 if (!_isPassive) //主动模式,等待Server的连接请求
205 {
206 _dataControler = _listener.AcceptTcpClient();
207 }
208 else
209 {
210 DisplayLocalMessage("正打开数据连接 IP: " + _transferEndPoint.ToString() + "\n");
211 _dataControler = new TcpClient();
212 _dataControler.Connect(_transferEndPoint);
213 }
214 }
215
216 public bool ReceiveList(ControlInfo controlInfo)
217 {
218 InitDataControler();
219
220 Send(controlInfo);
221 ReadReply(controlInfo);
222 Display(controlInfo.ReturnResult);
223
224 if (!controlInfo.Success)
225 {
226 Display(controlInfo.Parameter + " 传输失败!\n");
227 return false;
228 }
229 try
230 {
231 int startTime = Environment.TickCount;
232 NetworkStream ns = _dataControler.GetStream();
233 byte[] buffer = new byte[_dataControler.ReceiveBufferSize];
234 int totalSize = 0;
235 int dataSize = 0;
236 StringBuilder sb = new StringBuilder();
237
238
239 while ((dataSize = ns.Read(buffer, 0, _dataControler.ReceiveBufferSize)) > 0)
240 {
241 sb.Append(GetString(buffer, 0, dataSize));
242 totalSize += dataSize;
243 }
244 double useTime = GetUseTime(startTime, Environment.TickCount);
245 double speed = totalSize / useTime;
246 if (controlInfo.Parameter.Length == 0)
247 {
248 Display(sb.ToString());
249 }
250 else
251 {
252 FileStream fs = new FileStream(_currentDir + @"\" + controlInfo.Parameter, FileMode.Create);
253 StreamWriter sw = new StreamWriter(fs);
254 sw.Write(sb.ToString());
255 sw.Close();
256 fs.Close();
257 DisplayLocalMessage("列表已保存为: " + controlInfo.Parameter + ".\r\n");
258 }
259 //if(
260 ReadReply(controlInfo);
261 Display(controlInfo.ReturnResult);
262 DisplayLocalMessage("列表完成: " + totalSize + " bytes, use time " +
263 useTime.ToString("f2") + " Seconds (" + GetSpeed(speed) + ").\r\n");
264
265 return true;
266 }
267 catch (Exception e)
268 {
269 DisplayLocalMessage(e.Message);
270 return false;
271 }
272 }
273
274 private void DisplayCommand(string command)
275 {
276 Console.ForegroundColor = ConsoleColor.Yellow;
277 Console.Write(command);
278 Console.ForegroundColor = ConsoleColor.White;
279 }
280
281 private void DisplayLocalMessage(string message)
282 {
283 Console.ForegroundColor = ConsoleColor.Red;
284 Console.Write(message);
285 Console.ForegroundColor = ConsoleColor.White;
286 }
287
288 private IPEndPoint GetEndPoint(string strEndPoint)
289 {
290 string[] endPoints = strEndPoint.Split(',');
291 string remoteIP = endPoints[0] + "." + endPoints[1] + "."
292 + endPoints[2] + "." + endPoints[3];
293
294 //endp[4] X 256 + endp[5];
295 int port = (Convert.ToInt32(endPoints[4]) * 256) + (int.Parse(endPoints[5]));
296 IPAddress ip = IPAddress.Parse(remoteIP);
297 IPEndPoint remoteEP = new IPEndPoint(ip, port);
298
299 return remoteEP;
300 }
301
302 private void Send(ControlInfo controlInfo)
303 {
304 DisplayCommand(controlInfo.GetCommand());
305 NetworkStream ns = _commandControler.GetStream();
306 byte[] sendData = GetBytes(controlInfo.GetCommand());
307 ns.Write(sendData, 0, sendData.Length);
308 }
309
310 private void Send(string command)
311 {
312 DisplayCommand(command);
313 NetworkStream ns = _commandControler.GetStream();
314 byte[] sendData = GetBytes(command);
315 ns.Write(sendData, 0, sendData.Length);
316 }
317
318 public void ExcuteCommand(string command)
319 {
320 string cmd = "";
321 int index = 1;
322 bool isDone = false;
323 string paras = "";
324 for (; index <= command.Length && !isDone; index++)
325 {
326 cmd = command.Substring(0, index);
327 paras = command.Substring(index);
328 isDone = DoCommand(cmd, paras);
329 }
330 if(!isDone)
331 DisplayCommand("Invalid command.\r\n");
332 }
333
334 private bool DoCommand(string command, string parameter)
335 {
336 switch (command.ToLower())
337 {
338 case "get":
339 SetBinaryMode(true);
340 SetMode();
341 Excute("RETR" + parameter);
342 //FileInfo file = new FileInfo(parameter);
343 //File.
344 break;
345 case "put":
346 SetBinaryMode(true);
347 SetMode();
348 Excute("STOR" + parameter);
349 break;
350 case "dir":
351 Excute("PWD");
352 SetBinaryMode(false);
353 SetMode();
354 Excute("LIST" + parameter);
355 break;
356 case "pwd":
357 Excute("PWD");
358 break;
359 case "cd":
360 if (Excute("CWD" + parameter))
361 {
362 DoCommand("dir", "");
363 }
364 break;
365 case "?":
366 GetHelp(parameter.Trim());
367 break;
368 case "quit":
369 Excute("QUIT");
370 break;
371 case "user":
372 return Login(parameter);
373 default:
374 return false;
375 }
376 return true;
377 }
378
379 public bool Login(string usernameAndPassword)
380 {
381 int index = usernameAndPassword.IndexOf(" ", 1);
382 _username = usernameAndPassword.Substring(0, index).Trim();
383 _password = usernameAndPassword.Substring(index + 1).Trim();
384 if (Excute("USER " + _username))
385 {
386 if (Excute("PASS " + _password))
387 {
388 return true;
389 }
390 }
391 return false;
392 }
393
394 private void GetHelp(string para)
395 {
396 string message = "Invalid command.";
397 switch (para)
398 {
399 case "":
400 message="\t?\tget\tput\tdir\r\n\tcd\tquit";
401 break;
402 case "?":
403 message = "? 显示 ftp 命令说明.\r\n"
404 + "格式: ? [command]\r\n"
405 + "说明: [command]指定需要帮助的命令名称.如果没有指定 command,ftp 将显示全部命令的列表.";
406 break;
407 case "get":
408 message="get 使用当前文件转换类型将远程文件复制到本地计算机.\r\n"
409 +"格式: get remote-file [local-file]\r\n"
410 +"说明: remote-file 指定要复制的远程文件,\r\n"
411 +"local-file 指定要在本地计算机上使用的名称,若没指定,文件将命名为remote-file.";
412 break;
413 case "put":
414 message = "put 使用当前文件传送类型将本地文件复制到远程计算机上.\r\n"
415 + "格式: put local-file [remote-file]\r\n"
416 + "说明: local-file 指定要复制的本地文件,\r\n"
417 + "remote-file 指定要在远程计算机上使用的名称,若没指定,文件将命名为local-file.";
418 break;
419 case "dir":
420 message = "dir 显示远程目录文件和子目录列表.\r\n"
421 + "格式: dir [remote-directory] [local-file]\r\n"
422 + "说明: remote-directory 指定要查看其列表的目录.如果没有指定目录,将使用远程计算机中的当前工作目录,\r\n"
423 + "Local-file 指定要存储列表的本地文件.如果没有指定,输出将显示在屏幕上.";
424 break;
425 case "cd":
426 message = "cd 更改远程计算机上的工作目录.\r\n"
427 + "格式: cd remote-directory\r\n"
428 + "说明: remote-directory 指定要更改的远程计算机上的目录.";
429 break;
430 case "quit":
431 message = "quit 结束与远程计算机的 FTP 会话并退出 ftp.\r\n"
432 + "格式: quit";
433 break;
434 case "user":
435 message = "user 指定远程计算机的用户.\r\n"
436 + "格式: user username [password] [account]\r\n"
437 + "说明: username 指定登录到远程计算机所使用的用户名.\r\n"
438 + "password 指定 user-name 的密码.如果没有指定,但必须指定,ftp 会提示输入密码.";
439 break;
440 }
441 DisplayCommand(message + "\r\n");
442 }
443
444 private bool SetMode()
445 {
446 if (_isPassive)
447 {
448 return Excute("PASV");
449 }
450 else
451 {
452 return Excute("PORT");
453 }
454 }
455
456 public bool Excute(string command)
457 {
458 return Excute(ControlInfo.Create(command));
459 }
460
461 public bool Excute(ControlInfo controlInfo)
462 {
463 switch (controlInfo.Command)
464 {
465 //用户
466 case "USER":
467 Send(controlInfo);
468 ReadReply(controlInfo);
469 Display(controlInfo.ReturnResult);
470 break;
471 //密码
472 case "PASS":
473 Send(controlInfo);
474 ReadReply(controlInfo);
475 Display(controlInfo.ReturnResult);
476 break;
477 //EPSV
478 case "EPSV":
479 Send(controlInfo);
480 ReadReply(controlInfo);
481 Display(controlInfo.ReturnResult);
482 break;
483 //被动模式
484 case "PASV":
485 Send(controlInfo);
486 ReadReply(controlInfo);
487 Display(controlInfo.ReturnResult);
488 if (controlInfo.Success)
489 {
490 _isPassive = true;
491 SetTransferEndPoint(controlInfo.Message);
492 }
493 else
494 return false;
495 break;
496 //设定主动模式的数据连接端口
497 case "PORT":
498 return StartListener(controlInfo);
499 //文件及子目录列表
500 case "LIST":
501 return ReceiveList(controlInfo);
502 //下载文件
503 case "RETR":
504 return ReceiveData(controlInfo);
505 //名字系统类型
506 case "SYST":
507 Send(controlInfo);
508 ReadReply(controlInfo);
509 Display(controlInfo.ReturnResult);
510 break;
511 //上传文件
512 case "STOR":
513 return SendData(controlInfo);
514 //改变工作目录
515 case "CWD":
516 Send(controlInfo);
517 ReadReply(controlInfo);
518 Display(controlInfo.ReturnResult);
519 if (controlInfo.Success)
520 {
521 SetServerDir(controlInfo.Message);
522 }
523 else
524 {
525 return false;
526 }
527 break;
528 //当前目录
529 case "PWD":
530 Send(controlInfo);
531 ReadReply(controlInfo);
532 Display(controlInfo.ReturnResult);
533 break;
534 //传输模式
535 case "TYPE":
536 Send(controlInfo);
537 ReadReply(controlInfo);
538 Display(controlInfo.ReturnResult);
539 if (controlInfo.Success)
540 {
541 switch (controlInfo.Parameter)
542 {
543 case "I":
544 _isBinary = true;
545 break;
546 case "A":
547 _isBinary = false;
548 break;
549 }
550 }
551 break;
552 //退出
553 case "QUIT":
554 Send(controlInfo);
555 ReadReply(controlInfo);
556 Display(controlInfo.ReturnResult);
557 Close();
558 break;
559 default:
560 Display("This is '" + controlInfo.Command + "' not implemented.\n");
561 return false;
562 }
563 return true;
564 }
565
566 private void SetServerDir(string dir)
567 {
568 int startIndex = dir.IndexOf("to ") + 3;
569 int length = dir.LastIndexOf("\r\n") - startIndex;
570 _serverDir = dir.Substring(startIndex, length);
571 }
572
573 private bool SendData(ControlInfo controlInfo)
574 {
575 if (controlInfo.Parameter2.Length > 0)
576 {
577 Send(controlInfo.Command + " " + controlInfo.Parameter2 + "\r\n");
578 }
579 else
580 {
581 Send(controlInfo);
582 }
583 ReadReply(controlInfo);
584 Display(controlInfo.ReturnResult);
585
586 if (!controlInfo.Success)
587 {
588 Display("传送失败!\r\n");
589 return false;
590 }
591 InitDataControler();
592
593 try
594 {
595 int startTime = Environment.TickCount;
596
597 string file = _currentDir + @"\" + controlInfo.Parameter;
598 FileInfo fileInfo = new FileInfo(file);
599 if (!fileInfo.Exists)
600 {
601 Display(fileInfo.FullName + " : No such file.\r\n");
602 _dataControler.Close();
603 return false;
604 }
605 if (_isBinary)
606 {
607 _dataControler.Client.SendFile(file);
608
609 }
610 else
611 {
612 FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open);
613 StreamReader sr = new StreamReader(fs);
614 byte[] buffer = GetBytes(sr.ReadToEnd());
615 _dataControler.GetStream().Write(buffer, 0, buffer.Length);
616 sr.Close();
617 fs.Close();
618 }
619 _dataControler.Close();
620
621 controlInfo.SuccessCode = 226;
622 ReadReply(controlInfo);
623 Display(controlInfo.ReturnResult);
624 double useTime = GetUseTime(startTime, Environment.TickCount);
625 double speed = fileInfo.Length / useTime;
626
627 if (controlInfo.Success)
628 {
629 Display("已传送 " + controlInfo.Parameter + " " + fileInfo.Length + " bytes, use time " +
630 useTime.ToString("f2") + " Seconds (" + GetSpeed(speed) + ").\n");
631 //Display("已传数: " + controlInfo.Parameter + " " + fileInfo.Length + " bytes.\n");
632 }
633 else
634 {
635 Display(controlInfo.Parameter + " 传送失败!\r\n");
636 }
637 return true;
638 }
639 catch (Exception e)
640 {
641 DisplayLocalMessage(e.Message);
642 return false;
643 }
644 }
645
646 private void SetTransferEndPoint(string endPoint)
647 {
648 int offset = endPoint.IndexOf("(") + 1;
649 int length = endPoint.LastIndexOf(")") - offset;
650 endPoint = endPoint.Substring(offset, length);
651 _transferEndPoint = GetEndPoint(endPoint);
652 }
653
654 /**//// <summary>
655 /// 计算传输时间,以秒为单位
656 /// </summary>
657 /// <param name="startTime">开始的毫秒数</param>
658 /// <param name="endTime">结束的毫秒数</param>
659 /// <returns></returns>
660 private double GetUseTime(int startTime, int endTime)
661 {
662 double useTime = ((double)(endTime - startTime)) / 1000;
663 if (useTime == 0)
664 {
665 useTime = 0.01;
666 }
667 return useTime;
668 }
669
670 private string GetSpeed(double speed)
671 {
672 string unit = " Bytes/S";
673 if (speed > 1000)
674 {
675 speed = speed / 1000;
676 unit = " KB/S";
677 }
678 if (speed > 1000)
679 {
680 speed = speed / 1000;
681 unit = " MB/S";
682 }
683 if (speed > 1000)
684 {
685 speed /= 1000;
686 unit = " GB/S";
687 }
688 return speed.ToString("f2") + unit;
689 }
690
691 private bool StartListener(ControlInfo controlInfo)
692 {
693 int p = controlInfo.Parameter.Length > 0 ? Convert.ToInt32(controlInfo.Parameter) : 0;
694 IPEndPoint localEP = new IPEndPoint(_clientIP, p);
695 _listener = new TcpListener(localEP);
696 _listener.Start();
697 DisplayLocalMessage("已打开数据监听连接 IP:" + _listener.LocalEndpoint.ToString() + "\r\n");
698 //CultureInfo ci = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();
699 //NumberFormatInfo nfi = ci.NumberFormat;
700 /**/////Set our format to "123,456"
701 //nfi.CurrencyPositivePattern = 1;
702 //nfi.CurrencyGroupSeparator = ",";
703 //nfi.CurrencySymbol = "";
704 //nfi.CurrencyDecimalDigits = 0;
705 //ci.NumberFormat = nfi;
706
707 //Thread.CurrentThread.CurrentCulture = ci;
708 localEP = (IPEndPoint)_listener.LocalEndpoint;
709
710 string ip = localEP.Address.ToString().Replace(".", ",");
711 //string port = localEP.Port.ToString("C");
712 int p1 = localEP.Port / 256;
713 int p2 = localEP.Port % 256;
714 controlInfo.Parameter = ip + "," + p1 + "," + p2;
715
716 Send(controlInfo);
717 ReadReply(controlInfo);
718 Display(controlInfo.ReturnResult);
719 if (controlInfo.Success)
720 {
721 _isPassive = false;
722 }
723 else
724 return false;
725 return true;
726 }
727
728 private void Display(string str)
729 {
730 Console.ForegroundColor = ConsoleColor.Green;
731 Console.Write(str);
732 Console.ForegroundColor = ConsoleColor.White;
733 }
734
735 /**//// <summary>
736 /// 将字符串转换成UTF8码的字节数组,这样可以传输中文等
737 /// </summary>
738 /// <param name="response"></param>
739 /// <returns></returns>
740 private byte[] GetBytes(string response)
741 {
742 return GetBytes(response, Encoding.Default);
743 }
744
745 private byte[] GetBytes(string response, Encoding encoder)
746 {
747 return encoder.GetBytes(response.ToCharArray());
748 }
749
750 //private void Append(StringBuilder sb, byte[] data)
751 //{
752 // sb.Append(Encoding.Default.GetString(data));
753 //}
754
755 private string GetString(byte[] datas)
756 {
757 return GetString(datas, 0, datas.Length);
758 }
759
760 private string GetString(byte[] datas, int offset, int size)
761 {
762 return GetString(datas, offset, size, Encoding.Default);
763 }
764
765 private string GetString(byte[] datas, int offset, int size, Encoding encoder)
766 {
767 return encoder.GetString(datas, offset, size);
768 }
769 }
770}
771
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.IO;
5using System.Net;
6using System.Net.Sockets;
7using System.Threading;
8using System.Globalization;
9using System.Collections;
10
11namespace FtpClient
12{
13 public class FtpViewer
14 {
15 private TcpClient _commandControler;
16 private TcpListener _listener;
17 private TcpClient _dataControler;
18 private IPEndPoint _serverEndPoint;
19 private IPEndPoint _transferEndPoint;
20 private IPAddress _clientIP;
21 private string _username;
22 private string _password;
23 private string _currentDir;
24 private string _serverDir = @"\";
25 private bool _isPassive = true; //默认被动模式,采用二进制模式传输数据
26 private bool _isBinary = true;
27 private bool _isRunning = false;
28
29 public bool IsRunning
30 {
31 get { return _isRunning; }
32 set { _isRunning = value; }
33 }
34
35 public FtpViewer()
36 {
37
38 }
39
40 public FtpViewer(IPEndPoint serverEndPoint)
41 {
42 _clientIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
43 _serverEndPoint = serverEndPoint;
44 _commandControler = new TcpClient();
45 _currentDir = System.Environment.CurrentDirectory;
46 }
47
48 public void SetBinaryMode(bool isBinary)
49 {
50 if (isBinary != _isBinary)
51 {
52 _isBinary = isBinary;
53 if (isBinary)
54 {
55 Excute("TYPE I");
56 }
57 else
58 {
59 Excute("TYPE A");
60 }
61 }
62 }
63
64 public bool Start()
65 {
66 _commandControler.Connect(_serverEndPoint);
67 ControlInfo controlInfo = new ControlInfo();
68 ReadReply(controlInfo);
69 Display(controlInfo.ReturnResult);
70
71 DisplayCommand("User (" + _serverEndPoint.ToString() + ":) ");
72 Login(Console.ReadLine());
73
74 _isRunning = true;
75 return true;
76 }
77
78 public void Close()
79 {
80 if (_commandControler != null)
81 {
82 _commandControler.Close();
83 _commandControler = null;
84 }
85 if (_dataControler != null)
86 {
87 _dataControler.Close();
88 _dataControler = null;
89 }
90 _isRunning = false;
91 }
92
93 public bool ReadReply(ControlInfo controlInfo)
94 {
95 try
96 {
97 NetworkStream ns = _commandControler.GetStream();
98
99 byte[] buffer = new byte[_commandControler.ReceiveBufferSize];
100 int dataSize = ns.Read(buffer, 0, buffer.Length);
101 string result = GetString(buffer, 0, dataSize);
102
103 if (result.Length == 0)
104 {
105 controlInfo.ReturnCode = 0;
106 controlInfo.Message = "";
107 controlInfo.ReturnResult = "";
108 return true;
109 }
110
111 controlInfo.ReturnCode = Convert.ToInt32(result.Substring(0, 3));
112 controlInfo.Message = result.Substring(4);
113 controlInfo.ReturnResult = result;
114
115 return true;
116 }
117 catch(Exception e)
118 {
119 controlInfo.ReturnCode = 0;
120 controlInfo.Message = "";
121 controlInfo.ReturnResult = "";
122 DisplayLocalMessage(e.Message);
123 return false;
124 }
125 }
126
127 public bool ReceiveData(ControlInfo controlInfo)
128 {
129 InitDataControler();
130
131 Send(controlInfo);
132 ReadReply(controlInfo);
133 Display(controlInfo.ReturnResult);
134
135 if (!controlInfo.Success)
136 {
137 Display( controlInfo.Parameter + " 传输失败!\n");
138 return false;
139 }
140 try
141 {
142
143 int startTime = Environment.TickCount;
144
145 NetworkStream ns = _dataControler.GetStream();
146 string filename = controlInfo.Parameter2.Length > 0 ? controlInfo.Parameter2 : controlInfo.Parameter;
147
148 FileStream fs = new FileStream(_currentDir + @"\" + filename, FileMode.Create);
149 Int64 totalSize = 0;
150 if (_isBinary)
151 {
152 byte[] buffer = new byte[1024];
153
154 int dataSize = 0;
155
156 BinaryWriter bw = new BinaryWriter(fs);
157
158 while ((dataSize = ns.Read(buffer, 0, buffer.Length)) > 0)
159 {
160 totalSize += dataSize;
161 bw.Write(buffer, 0, dataSize);
162 }
163
164 bw.Close();
165 }
166 else
167 {
168 //ArrayList datas = new ArrayList();
169 //StreamWriter sw
170 //while ((dataSize = ns.Read(buffer, 0, buffer.Length)) > 0)
171 //{
172 // //sw.Write(Encoding.UTF8.GetChars(buffer, 0, dataSize),
173 // //0, dataSize);
174 //}
175
176 //StreamWriter sw = new StreamWriter(fs);
177 //sw.Write(Encoding.UTF8.GetString(buffer, 0, dataSize));
178 //Display("已传送 " + controlInfo.Parameter + " " + fs.Length + " bytes. \n");
179 //sw.Close();
180 }
181
182 fs.Close();
183 ns.Close();
184 _dataControler.Close();
185 ReadReply(controlInfo);
186 Display(controlInfo.ReturnResult);
187 double useTime = GetUseTime(startTime, Environment.TickCount);
188 double speed = totalSize / useTime;
189
190 Display("已传送 " + filename + " " + totalSize + " bytes, use time " +
191 useTime.ToString("f2") + " Seconds (" + GetSpeed(speed) + ").\n");
192
193 return true;
194 }
195 catch (Exception e)
196 {
197 DisplayLocalMessage(e.Message);
198 return false;
199 }
200 }
201
202 private void InitDataControler()
203 {
204 if (!_isPassive) //主动模式,等待Server的连接请求
205 {
206 _dataControler = _listener.AcceptTcpClient();
207 }
208 else
209 {
210 DisplayLocalMessage("正打开数据连接 IP: " + _transferEndPoint.ToString() + "\n");
211 _dataControler = new TcpClient();
212 _dataControler.Connect(_transferEndPoint);
213 }
214 }
215
216 public bool ReceiveList(ControlInfo controlInfo)
217 {
218 InitDataControler();
219
220 Send(controlInfo);
221 ReadReply(controlInfo);
222 Display(controlInfo.ReturnResult);
223
224 if (!controlInfo.Success)
225 {
226 Display(controlInfo.Parameter + " 传输失败!\n");
227 return false;
228 }
229 try
230 {
231 int startTime = Environment.TickCount;
232 NetworkStream ns = _dataControler.GetStream();
233 byte[] buffer = new byte[_dataControler.ReceiveBufferSize];
234 int totalSize = 0;
235 int dataSize = 0;
236 StringBuilder sb = new StringBuilder();
237
238
239 while ((dataSize = ns.Read(buffer, 0, _dataControler.ReceiveBufferSize)) > 0)
240 {
241 sb.Append(GetString(buffer, 0, dataSize));
242 totalSize += dataSize;
243 }
244 double useTime = GetUseTime(startTime, Environment.TickCount);
245 double speed = totalSize / useTime;
246 if (controlInfo.Parameter.Length == 0)
247 {
248 Display(sb.ToString());
249 }
250 else
251 {
252 FileStream fs = new FileStream(_currentDir + @"\" + controlInfo.Parameter, FileMode.Create);
253 StreamWriter sw = new StreamWriter(fs);
254 sw.Write(sb.ToString());
255 sw.Close();
256 fs.Close();
257 DisplayLocalMessage("列表已保存为: " + controlInfo.Parameter + ".\r\n");
258 }
259 //if(
260 ReadReply(controlInfo);
261 Display(controlInfo.ReturnResult);
262 DisplayLocalMessage("列表完成: " + totalSize + " bytes, use time " +
263 useTime.ToString("f2") + " Seconds (" + GetSpeed(speed) + ").\r\n");
264
265 return true;
266 }
267 catch (Exception e)
268 {
269 DisplayLocalMessage(e.Message);
270 return false;
271 }
272 }
273
274 private void DisplayCommand(string command)
275 {
276 Console.ForegroundColor = ConsoleColor.Yellow;
277 Console.Write(command);
278 Console.ForegroundColor = ConsoleColor.White;
279 }
280
281 private void DisplayLocalMessage(string message)
282 {
283 Console.ForegroundColor = ConsoleColor.Red;
284 Console.Write(message);
285 Console.ForegroundColor = ConsoleColor.White;
286 }
287
288 private IPEndPoint GetEndPoint(string strEndPoint)
289 {
290 string[] endPoints = strEndPoint.Split(',');
291 string remoteIP = endPoints[0] + "." + endPoints[1] + "."
292 + endPoints[2] + "." + endPoints[3];
293
294 //endp[4] X 256 + endp[5];
295 int port = (Convert.ToInt32(endPoints[4]) * 256) + (int.Parse(endPoints[5]));
296 IPAddress ip = IPAddress.Parse(remoteIP);
297 IPEndPoint remoteEP = new IPEndPoint(ip, port);
298
299 return remoteEP;
300 }
301
302 private void Send(ControlInfo controlInfo)
303 {
304 DisplayCommand(controlInfo.GetCommand());
305 NetworkStream ns = _commandControler.GetStream();
306 byte[] sendData = GetBytes(controlInfo.GetCommand());
307 ns.Write(sendData, 0, sendData.Length);
308 }
309
310 private void Send(string command)
311 {
312 DisplayCommand(command);
313 NetworkStream ns = _commandControler.GetStream();
314 byte[] sendData = GetBytes(command);
315 ns.Write(sendData, 0, sendData.Length);
316 }
317
318 public void ExcuteCommand(string command)
319 {
320 string cmd = "";
321 int index = 1;
322 bool isDone = false;
323 string paras = "";
324 for (; index <= command.Length && !isDone; index++)
325 {
326 cmd = command.Substring(0, index);
327 paras = command.Substring(index);
328 isDone = DoCommand(cmd, paras);
329 }
330 if(!isDone)
331 DisplayCommand("Invalid command.\r\n");
332 }
333
334 private bool DoCommand(string command, string parameter)
335 {
336 switch (command.ToLower())
337 {
338 case "get":
339 SetBinaryMode(true);
340 SetMode();
341 Excute("RETR" + parameter);
342 //FileInfo file = new FileInfo(parameter);
343 //File.
344 break;
345 case "put":
346 SetBinaryMode(true);
347 SetMode();
348 Excute("STOR" + parameter);
349 break;
350 case "dir":
351 Excute("PWD");
352 SetBinaryMode(false);
353 SetMode();
354 Excute("LIST" + parameter);
355 break;
356 case "pwd":
357 Excute("PWD");
358 break;
359 case "cd":
360 if (Excute("CWD" + parameter))
361 {
362 DoCommand("dir", "");
363 }
364 break;
365 case "?":
366 GetHelp(parameter.Trim());
367 break;
368 case "quit":
369 Excute("QUIT");
370 break;
371 case "user":
372 return Login(parameter);
373 default:
374 return false;
375 }
376 return true;
377 }
378
379 public bool Login(string usernameAndPassword)
380 {
381 int index = usernameAndPassword.IndexOf(" ", 1);
382 _username = usernameAndPassword.Substring(0, index).Trim();
383 _password = usernameAndPassword.Substring(index + 1).Trim();
384 if (Excute("USER " + _username))
385 {
386 if (Excute("PASS " + _password))
387 {
388 return true;
389 }
390 }
391 return false;
392 }
393
394 private void GetHelp(string para)
395 {
396 string message = "Invalid command.";
397 switch (para)
398 {
399 case "":
400 message="\t?\tget\tput\tdir\r\n\tcd\tquit";
401 break;
402 case "?":
403 message = "? 显示 ftp 命令说明.\r\n"
404 + "格式: ? [command]\r\n"
405 + "说明: [command]指定需要帮助的命令名称.如果没有指定 command,ftp 将显示全部命令的列表.";
406 break;
407 case "get":
408 message="get 使用当前文件转换类型将远程文件复制到本地计算机.\r\n"
409 +"格式: get remote-file [local-file]\r\n"
410 +"说明: remote-file 指定要复制的远程文件,\r\n"
411 +"local-file 指定要在本地计算机上使用的名称,若没指定,文件将命名为remote-file.";
412 break;
413 case "put":
414 message = "put 使用当前文件传送类型将本地文件复制到远程计算机上.\r\n"
415 + "格式: put local-file [remote-file]\r\n"
416 + "说明: local-file 指定要复制的本地文件,\r\n"
417 + "remote-file 指定要在远程计算机上使用的名称,若没指定,文件将命名为local-file.";
418 break;
419 case "dir":
420 message = "dir 显示远程目录文件和子目录列表.\r\n"
421 + "格式: dir [remote-directory] [local-file]\r\n"
422 + "说明: remote-directory 指定要查看其列表的目录.如果没有指定目录,将使用远程计算机中的当前工作目录,\r\n"
423 + "Local-file 指定要存储列表的本地文件.如果没有指定,输出将显示在屏幕上.";
424 break;
425 case "cd":
426 message = "cd 更改远程计算机上的工作目录.\r\n"
427 + "格式: cd remote-directory\r\n"
428 + "说明: remote-directory 指定要更改的远程计算机上的目录.";
429 break;
430 case "quit":
431 message = "quit 结束与远程计算机的 FTP 会话并退出 ftp.\r\n"
432 + "格式: quit";
433 break;
434 case "user":
435 message = "user 指定远程计算机的用户.\r\n"
436 + "格式: user username [password] [account]\r\n"
437 + "说明: username 指定登录到远程计算机所使用的用户名.\r\n"
438 + "password 指定 user-name 的密码.如果没有指定,但必须指定,ftp 会提示输入密码.";
439 break;
440 }
441 DisplayCommand(message + "\r\n");
442 }
443
444 private bool SetMode()
445 {
446 if (_isPassive)
447 {
448 return Excute("PASV");
449 }
450 else
451 {
452 return Excute("PORT");
453 }
454 }
455
456 public bool Excute(string command)
457 {
458 return Excute(ControlInfo.Create(command));
459 }
460
461 public bool Excute(ControlInfo controlInfo)
462 {
463 switch (controlInfo.Command)
464 {
465 //用户
466 case "USER":
467 Send(controlInfo);
468 ReadReply(controlInfo);
469 Display(controlInfo.ReturnResult);
470 break;
471 //密码
472 case "PASS":
473 Send(controlInfo);
474 ReadReply(controlInfo);
475 Display(controlInfo.ReturnResult);
476 break;
477 //EPSV
478 case "EPSV":
479 Send(controlInfo);
480 ReadReply(controlInfo);
481 Display(controlInfo.ReturnResult);
482 break;
483 //被动模式
484 case "PASV":
485 Send(controlInfo);
486 ReadReply(controlInfo);
487 Display(controlInfo.ReturnResult);
488 if (controlInfo.Success)
489 {
490 _isPassive = true;
491 SetTransferEndPoint(controlInfo.Message);
492 }
493 else
494 return false;
495 break;
496 //设定主动模式的数据连接端口
497 case "PORT":
498 return StartListener(controlInfo);
499 //文件及子目录列表
500 case "LIST":
501 return ReceiveList(controlInfo);
502 //下载文件
503 case "RETR":
504 return ReceiveData(controlInfo);
505 //名字系统类型
506 case "SYST":
507 Send(controlInfo);
508 ReadReply(controlInfo);
509 Display(controlInfo.ReturnResult);
510 break;
511 //上传文件
512 case "STOR":
513 return SendData(controlInfo);
514 //改变工作目录
515 case "CWD":
516 Send(controlInfo);
517 ReadReply(controlInfo);
518 Display(controlInfo.ReturnResult);
519 if (controlInfo.Success)
520 {
521 SetServerDir(controlInfo.Message);
522 }
523 else
524 {
525 return false;
526 }
527 break;
528 //当前目录
529 case "PWD":
530 Send(controlInfo);
531 ReadReply(controlInfo);
532 Display(controlInfo.ReturnResult);
533 break;
534 //传输模式
535 case "TYPE":
536 Send(controlInfo);
537 ReadReply(controlInfo);
538 Display(controlInfo.ReturnResult);
539 if (controlInfo.Success)
540 {
541 switch (controlInfo.Parameter)
542 {
543 case "I":
544 _isBinary = true;
545 break;
546 case "A":
547 _isBinary = false;
548 break;
549 }
550 }
551 break;
552 //退出
553 case "QUIT":
554 Send(controlInfo);
555 ReadReply(controlInfo);
556 Display(controlInfo.ReturnResult);
557 Close();
558 break;
559 default:
560 Display("This is '" + controlInfo.Command + "' not implemented.\n");
561 return false;
562 }
563 return true;
564 }
565
566 private void SetServerDir(string dir)
567 {
568 int startIndex = dir.IndexOf("to ") + 3;
569 int length = dir.LastIndexOf("\r\n") - startIndex;
570 _serverDir = dir.Substring(startIndex, length);
571 }
572
573 private bool SendData(ControlInfo controlInfo)
574 {
575 if (controlInfo.Parameter2.Length > 0)
576 {
577 Send(controlInfo.Command + " " + controlInfo.Parameter2 + "\r\n");
578 }
579 else
580 {
581 Send(controlInfo);
582 }
583 ReadReply(controlInfo);
584 Display(controlInfo.ReturnResult);
585
586 if (!controlInfo.Success)
587 {
588 Display("传送失败!\r\n");
589 return false;
590 }
591 InitDataControler();
592
593 try
594 {
595 int startTime = Environment.TickCount;
596
597 string file = _currentDir + @"\" + controlInfo.Parameter;
598 FileInfo fileInfo = new FileInfo(file);
599 if (!fileInfo.Exists)
600 {
601 Display(fileInfo.FullName + " : No such file.\r\n");
602 _dataControler.Close();
603 return false;
604 }
605 if (_isBinary)
606 {
607 _dataControler.Client.SendFile(file);
608
609 }
610 else
611 {
612 FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open);
613 StreamReader sr = new StreamReader(fs);
614 byte[] buffer = GetBytes(sr.ReadToEnd());
615 _dataControler.GetStream().Write(buffer, 0, buffer.Length);
616 sr.Close();
617 fs.Close();
618 }
619 _dataControler.Close();
620
621 controlInfo.SuccessCode = 226;
622 ReadReply(controlInfo);
623 Display(controlInfo.ReturnResult);
624 double useTime = GetUseTime(startTime, Environment.TickCount);
625 double speed = fileInfo.Length / useTime;
626
627 if (controlInfo.Success)
628 {
629 Display("已传送 " + controlInfo.Parameter + " " + fileInfo.Length + " bytes, use time " +
630 useTime.ToString("f2") + " Seconds (" + GetSpeed(speed) + ").\n");
631 //Display("已传数: " + controlInfo.Parameter + " " + fileInfo.Length + " bytes.\n");
632 }
633 else
634 {
635 Display(controlInfo.Parameter + " 传送失败!\r\n");
636 }
637 return true;
638 }
639 catch (Exception e)
640 {
641 DisplayLocalMessage(e.Message);
642 return false;
643 }
644 }
645
646 private void SetTransferEndPoint(string endPoint)
647 {
648 int offset = endPoint.IndexOf("(") + 1;
649 int length = endPoint.LastIndexOf(")") - offset;
650 endPoint = endPoint.Substring(offset, length);
651 _transferEndPoint = GetEndPoint(endPoint);
652 }
653
654 /**//// <summary>
655 /// 计算传输时间,以秒为单位
656 /// </summary>
657 /// <param name="startTime">开始的毫秒数</param>
658 /// <param name="endTime">结束的毫秒数</param>
659 /// <returns></returns>
660 private double GetUseTime(int startTime, int endTime)
661 {
662 double useTime = ((double)(endTime - startTime)) / 1000;
663 if (useTime == 0)
664 {
665 useTime = 0.01;
666 }
667 return useTime;
668 }
669
670 private string GetSpeed(double speed)
671 {
672 string unit = " Bytes/S";
673 if (speed > 1000)
674 {
675 speed = speed / 1000;
676 unit = " KB/S";
677 }
678 if (speed > 1000)
679 {
680 speed = speed / 1000;
681 unit = " MB/S";
682 }
683 if (speed > 1000)
684 {
685 speed /= 1000;
686 unit = " GB/S";
687 }
688 return speed.ToString("f2") + unit;
689 }
690
691 private bool StartListener(ControlInfo controlInfo)
692 {
693 int p = controlInfo.Parameter.Length > 0 ? Convert.ToInt32(controlInfo.Parameter) : 0;
694 IPEndPoint localEP = new IPEndPoint(_clientIP, p);
695 _listener = new TcpListener(localEP);
696 _listener.Start();
697 DisplayLocalMessage("已打开数据监听连接 IP:" + _listener.LocalEndpoint.ToString() + "\r\n");
698 //CultureInfo ci = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();
699 //NumberFormatInfo nfi = ci.NumberFormat;
700 /**/////Set our format to "123,456"
701 //nfi.CurrencyPositivePattern = 1;
702 //nfi.CurrencyGroupSeparator = ",";
703 //nfi.CurrencySymbol = "";
704 //nfi.CurrencyDecimalDigits = 0;
705 //ci.NumberFormat = nfi;
706
707 //Thread.CurrentThread.CurrentCulture = ci;
708 localEP = (IPEndPoint)_listener.LocalEndpoint;
709
710 string ip = localEP.Address.ToString().Replace(".", ",");
711 //string port = localEP.Port.ToString("C");
712 int p1 = localEP.Port / 256;
713 int p2 = localEP.Port % 256;
714 controlInfo.Parameter = ip + "," + p1 + "," + p2;
715
716 Send(controlInfo);
717 ReadReply(controlInfo);
718 Display(controlInfo.ReturnResult);
719 if (controlInfo.Success)
720 {
721 _isPassive = false;
722 }
723 else
724 return false;
725 return true;
726 }
727
728 private void Display(string str)
729 {
730 Console.ForegroundColor = ConsoleColor.Green;
731 Console.Write(str);
732 Console.ForegroundColor = ConsoleColor.White;
733 }
734
735 /**//// <summary>
736 /// 将字符串转换成UTF8码的字节数组,这样可以传输中文等
737 /// </summary>
738 /// <param name="response"></param>
739 /// <returns></returns>
740 private byte[] GetBytes(string response)
741 {
742 return GetBytes(response, Encoding.Default);
743 }
744
745 private byte[] GetBytes(string response, Encoding encoder)
746 {
747 return encoder.GetBytes(response.ToCharArray());
748 }
749
750 //private void Append(StringBuilder sb, byte[] data)
751 //{
752 // sb.Append(Encoding.Default.GetString(data));
753 //}
754
755 private string GetString(byte[] datas)
756 {
757 return GetString(datas, 0, datas.Length);
758 }
759
760 private string GetString(byte[] datas, int offset, int size)
761 {
762 return GetString(datas, offset, size, Encoding.Default);
763 }
764
765 private string GetString(byte[] datas, int offset, int size, Encoding encoder)
766 {
767 return encoder.GetString(datas, offset, size);
768 }
769 }
770}
771
代码未经整理,呵呵,等寒假再回来重构一下.