Новичок
Профиль
Группа: Участник
Сообщений: 15
Регистрация: 16.10.2009
Репутация: нет Всего: нет
|
Название темы: "[C#] FTP клиент. Переделать с пассивного в актиный режим обмена"Всем добрый вечер! Есть FTP клиент, реализующий команды USER, PASS, RETR, STOR, RESt, Quit, LIST и PWD Режим обмена с сервером - пассивный. Необходимо переделать в активный режим. Нужна ваша помощь! Ниже привожу код FTP.csКод |
using System; using System.IO; using System.Net; using System.Net.Sockets; using System.Text; using System.Text.RegularExpressions; using System.Collections;
namespace ftp { public class FTP { public string server; public string user; public string pass; public int port; public int timeout;
private string responseStr; private long bytes_total; private Socket main_sock; private IPEndPoint main_ipEndPoint; private Socket data_sock; private IPEndPoint data_ipEndPoint; private FileStream file; private int response; private string bucket; public FTP(string server, int port, string user, string pass) { this.server = server; this.user = user; this.pass = pass; this.port = port; main_sock = null; main_ipEndPoint = null; data_sock = null; data_ipEndPoint = null; file = null; bucket = ""; bytes_total = 0; timeout = 10000; // 10 секунд }
public bool IsConnected { get { return main_sock != null && main_sock.Connected; } } public string ResponseString { get { return responseStr; } } public long BytesTotal { get { return bytes_total; } } private void Fail() { Disconnect(); throw new Exception(responseStr); } // отправляет команду в сокет private void SendCommand(string command) { Byte[] cmd = Encoding.ASCII.GetBytes((command + "\r\n").ToCharArray()); main_sock.Send(cmd, cmd.Length, 0); } // дожидается приема данных. Если даные пришли, то bucket +=, иначе выход по тайм-ауту private void FillBucket() { Byte[] bytes = new Byte[512]; int msecs_passed = 0; // крутимся здесь, пока не получим ответ или тайм-аут while(main_sock.Available < 1) { System.Threading.Thread.Sleep(50); msecs_passed += 50; if (msecs_passed > timeout) { Disconnect(); throw new Exception("Timed out waiting on server to respond."); } } // пытаемся прочитать данные while(main_sock.Available > 0) { long bytesgot = main_sock.Receive(bytes, 512, 0); bucket += Encoding.ASCII.GetString(bytes, 0, (int)bytesgot); System.Threading.Thread.Sleep(50); } } // из буфера bucket извлекаем строку (до '\n') private string GetLineFromBucket() { int i; if ((i = bucket.IndexOf('\n')) < 0) { while(i < 0) { FillBucket(); i = bucket.IndexOf('\n'); } } string buf = bucket.Substring(0, i); bucket = bucket.Substring(i + 1); return buf; } // читаем ответ от сервера // responseStr содержит прочитанную функцию
private void ReadResponse() { string buf;
while(true) { // читаем строку из вх.буфера buf = GetLineFromBucket(); if (Regex.Match(buf, "^[0-9]+ ").Success) { responseStr = buf; response = int.Parse(buf.Substring(0, 3)); break; } } } [color=red] // открывает сокет в пассивном режиме private void OpenDataSocket() { string[] pasv;
Connect(); SendCommand("PASV"); ReadResponse(); if (response != 227) Fail(); // извлекаем инфу об IP:port от сервера try { int i1 = responseStr.IndexOf('(') + 1; int i2 = responseStr.IndexOf(')') - i1; pasv = responseStr.Substring(i1, i2).Split(','); } catch (Exception) { Disconnect(); throw new Exception("Malformed PASV response: " + responseStr); } // д.б. 4 эл-та IP + 2 эл-та порта if (pasv.Length < 6) { Disconnect(); throw new Exception("Malformed PASV response: " + responseStr); } // восстанавливаем IP-адрес сервера и порт string server_ = String.Format("{0}.{1}.{2}.{3}", pasv[0], pasv[1], pasv[2], pasv[3]); int port_ = (int.Parse(pasv[4]) << 8) + int.Parse(pasv[5]); try { // закрываем текущее соединеие для данных CloseDataSocket(); // создаем подключение к новому порту data_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); data_sock.ReceiveTimeout = 10000; data_sock.SendTimeout = 10000; data_ipEndPoint = new IPEndPoint(Dns.GetHostEntry(server_).AddressList[0], port_); data_sock.Connect(data_ipEndPoint); } catch (Exception ex) { throw new Exception("Failed to connect for data transfer: " + ex.Message); } }[/color] // закрываем соединение для данных private void CloseDataSocket() { if (data_sock != null) { if (data_sock.Connected) data_sock.Close(); data_sock = null; } data_ipEndPoint = null; } // закрываем все соединения, открытые для работы с сокетом public void Disconnect() { CloseDataSocket(); if (main_sock != null) { if (main_sock.Connected) { SendCommand("QUIT"); ReadResponse(); main_sock.Close(); } main_sock = null; } if (file != null) file.Close(); main_ipEndPoint = null; file = null; } // подключение с указанием сервера, порта, имени пользователя и пароля public void Connect(string server_, int port_, string user_, string pass_) { server = server_; user = user_; pass = pass_; port = port_;
Connect(); } // создает управляющее подключение public void Connect() { //проверяем все параметры if (server == null) throw new Exception("No server has been set."); if (user == null) throw new Exception("No username has been set.");
if (main_sock != null) if (main_sock.Connected) return;
//создаем подключение main_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); main_sock.ReceiveTimeout = 10000; main_sock.SendTimeout = 10000; main_ipEndPoint = new IPEndPoint(Dns.GetHostEntry(server).AddressList[0], port); // пытаемся подключиться try { main_sock.Connect(main_ipEndPoint); } catch(Exception ex) { throw new Exception(ex.Message); }
// читаем ответ ReadResponse(); if (response != 220) Fail();
// отправляем имя пользователя и пароль SendCommand("USER " + user); ReadResponse();
switch(response) { case 331: if (pass == null) { Disconnect(); throw new Exception("No password has been set."); } SendCommand("PASS " + pass); ReadResponse(); if (response != 230) Fail(); break; // мы подключились case 230: break; }
SetASCIIMode(); return; } // получает список файлов на удаленном сервере public ArrayList List() { Byte[] bytes = new Byte[512]; string file_list = String.Empty; int msecs_passed = 0; ArrayList list = new ArrayList(); Connect(); // !!!!!!!!!!!!!!!!!!! OpenDataSocket(); SendCommand("LIST"); ReadResponse();
switch(response) { // все хорошо case 125: case 150: break; // плохо default: CloseDataSocket(); throw new Exception(responseStr); }
// если ответов еще нету, то ожидаем while(data_sock.Available < 1) { System.Threading.Thread.Sleep(50); msecs_passed += 50; if (msecs_passed > (timeout / 10)) break; }
// данные все-таки есть? while(data_sock.Available > 0) { long bytesgot = data_sock.Receive(bytes, bytes.Length, 0); file_list += Encoding.ASCII.GetString(bytes, 0, (int)bytesgot); //!!!!!!!!!!!!!!!!!!!!!!!!!!!! System.Threading.Thread.Sleep(50); } CloseDataSocket(); // получаем итоговый ответ от сервера ReadResponse(); if (response != 226) throw new Exception(responseStr);
// преобразуем string -> ArrayList foreach(string f in file_list.Split('\n')) { if (f.Length > 0 && !Regex.Match(f, "^total").Success) list.Add(f.Substring(0, f.Length - 1)); }
return list; } // смена директории public void ChangeDir(string path) { Connect(); SendCommand("CWD " + path); ReadResponse(); if (response != 250) throw new Exception(responseStr); }
// получить размер файла public long GetFileSize(string filename) { Connect(); SendCommand("SIZE " + filename); ReadResponse(); if (response != 213) throw new Exception(responseStr); return Int64.Parse(responseStr.Substring(4)); } // испр. на ASCII private void SetASCIIMode() { SendCommand("TYPE A"); ReadResponse(); if (response != 200) Fail(); } // загрузить файл на сервер с докачкой public void OpenUpload(string filename, string remote_filename, bool resume) { OpenDataSocket(); bytes_total = 0; try { file = new FileStream(filename, FileMode.Open); } catch(Exception ex) { file = null; throw new Exception(ex.Message); } // если восст. докачку, то посылаем команду восст. докачки if (resume) { // для этого определяем, докуда докачали long size = GetFileSize(remote_filename); SendCommand("REST " + size); ReadResponse(); if (response == 350) file.Seek(size, SeekOrigin.Begin); } // сохраняем файл на сервер SendCommand("STOR " + remote_filename); ReadResponse(); switch(response) { // все нормально case 125: case 150: break; default: file.Close(); file = null; throw new Exception(responseStr); } return; } // загружает файл на сервер, пока не будет скачан public long DoUpload(bool isAbort) { Byte[] bytes = new Byte[512]; long bytes_got;
try { bytes_got = file.Read(bytes, 0, bytes.Length); bytes_total += bytes_got; data_sock.Send(bytes, (int)bytes_got, 0);
if(bytes_got <= 0 || isAbort) { // файл докачан file.Close(); file = null; CloseDataSocket(); ReadResponse(); switch(response) { case 226: case 250: break; default: throw new Exception(responseStr); } } } catch(Exception) { file.Close(); file = null; CloseDataSocket(); ReadResponse(); throw; }
return isAbort ? 0 : bytes_got; } } }
|
|