Перейти из форума на сайт.

НовостиФайловые архивы
ПоискАктивные темыТоп лист
ПравилаКто в on-line?
Вход Забыли пароль? Первый раз на этом сайте? Регистрация
Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » FTP Client на C#

Модерирует : ShIvADeSt

 Версия для печати • ПодписатьсяДобавить в закладки
Страницы: 1 2

Открыть новую тему     Написать ответ в эту тему

AndrewWork

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Доброго времени суток.
Приведу часть программы, которая получает список дирикторий с сервера.
public string ListDir()
{
string command ="";
Socket sss = getDataSocket ();
command = "LIST";
command +="\r\n" ;
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);
Response();
 
Byte[] readBytes;
int sizeReceived;
string serverMessage = "";
do  
{
readBytes       = new Byte[READ_BUFFER_SIZE];
sizeReceived    = sss.Receive(readBytes, readBytes.Length, SocketFlags.None);
serverMessage  += Encoding.ASCII.GetString(readBytes, 0, sizeReceived);
if ( sizeReceived == 0 ) break ;  
}
while (true);  //sizeReceived == readBytes.Length & !serverMessage.EndsWith("\r\n")); // Go back for more if necessary

return serverMessage;
if (firstTime)
{
Response();
firstTime = false;
}


}
private Socket getDataSocket ()  
{
Socket pasvSocket;
string  command = "PASV";//PASV:Specifies that the server data transfer process is to listen for a connection request from the client data transfer process.  
command += "\r\n";
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);

//if(firstTime)
//{
// Response();
// firstTime=false;
//}
// Get server IP and port address, response sample is: .... (196,1,64,106,5,129)
string fullAddress =Response();
if (fullAddress.Substring(0,3) != "227")
{
fullAddress =Response();
}
fullAddress = fullAddress.Remove(0, fullAddress.IndexOf('(') + 1);//takes only what is  
fullAddress = fullAddress.Substring(0, fullAddress.IndexOf(')'));//between paranthesis
string[] addressParts = fullAddress.Split(',');
string pasvAddress = addressParts[0] + "." + addressParts[1] + "." + addressParts[2] + "." + addressParts[3];
int    pasvPort    = Convert.ToInt32(addressParts[4]) * 256 + Convert.ToInt32(addressParts[5]);

// Open the Data socket
pasvSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
pasvSocket.Connect(new IPEndPoint(IPAddress.Parse(pasvAddress),pasvPort));

return pasvSocket;//return the created socket
}
 
Возможно моя участь быть избитым ногами, но всё же осмелюсь спросить - кирилицу получить (в виде русских папок и т.п.) таким образом не получается, где грабли ?
Если нет возможности обяснить - ткните меня куда-нть шоб почитать для самообразования. За любую ценную информацию буду благодарен.

Всего записей: 77 | Зарегистр. 17-03-2003 | Отправлено: 02:45 09-05-2003
v0yager



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
как минимум, одна собака зарыта здесь:
 

Цитата:
serverMessage  += Encoding.ASCII.GetString(readBytes, 0, sizeReceived);

 
из MSDN:
 

Цитата:
The ASCIIEncoding class encodes Unicode characters as single 7-bit ASCII characters. This encoding only supports character values between U+0000 and U+007F.

 
ASCII encoding работает только с латиницей, кириллица не проходит. Для работы с кириллицей можно получить Encoding для кодовой страницы 1251. См. описание Encoding.GetEncoding(...).
 
Идею решения можно взять из следующего примера:
 

Код:
 
// a b c      а б в г д ж з      a b c
System.Byte[] dataWithRussianChars = {0x61,0x62,0x63, 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7, 0x61,0x62,0x63};
 
// получить Ecoding для заданной кодовой страницы
System.Text.Encoding enc = System.Text.Encoding.GetEncoding(1251);  
 
// посмотреть на результат
System.Console.WriteLine(enc.GetString(dataWithRussianChars));
 
// убедиться, что ASCII таки не пропускает кириллицу
System.Console.WriteLine(System.Text.Encoding.ASCII.GetString(dataWithRussianChars));
 
// остановить время
System.Console.ReadLine();
 

 

Всего записей: 95 | Зарегистр. 08-05-2003 | Отправлено: 19:23 09-05-2003
AndrewWork

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Огромное спасибо, v0yager.
 
Если это не будет наглостью ... у меня ещё маленький вопросик.
Меня интересует установка коннекта на PORT mode.
Команда PORT 10,1,1,1,17,171 передаёт значения ip адреса - 10.1.1.1 и порта по которому будут передаваться данные - port№ = 17*256+171 = 4523. При данной установке связи порт назначает клиент, тобишь я. А вот как выбирать у себя порт правильно ? Для FTP и т.п. сессия, как я понял есть диапазон портов от 1025 до 5000. Так что, просто рандомайзом ? К сожалению пока что никаких указаний на этот счёт в стандартах я не нашёл. Кто что знает/думает/полагает на этот счёт ?

Всего записей: 77 | Зарегистр. 17-03-2003 | Отправлено: 03:10 10-05-2003
v0yager



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
при PORT mode connect для создания канала данных будет идти от сервера к клиенту. При этом нужно быть готовым к борьбе с трудностями (если есть firewall). Для справки см. All About FTP
 
Порт при этом действительно выбирает клиент, можно и рандомом. В общем случае он может быть от 1024 до 65535. Порт и адрес (в терминах .NET - EndPoint) - любая свободная комбинация. Если есть firewall - нужно дополнительно учитывать его конфигурацию.
 
А вот тут появляется одно "НО". Причем большое. По дефолту в WinNT (начиная с 3.51 и до Win2K всех вариантов) у локального порта исходящего соединения номер может быть до 5000. При желании можно расширить диапазон - Unable to Connect from TCP Ports Above 5000. Но лучше на это не закладываться. Для универсальности желательно использовать порты 1024 - 5000.
 
Добавлено
Ограничение в 5000 может помешать FTP серверу IIS при дефалтовых установках установить соединение с ftp-клиентов, даже если все остальные условия (firewall, порт свободен,...) будут выполнены.
 

Всего записей: 95 | Зарегистр. 08-05-2003 | Отправлено: 15:45 10-05-2003 | Исправлено: v0yager, 15:52 10-05-2003
AndrewWork

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Странно, но у меня как-то не получилось вот просто так подконнектиться по порту выбранному рандомом
Я делал так :
 
IPAddress localAddress = ((IPEndPoint)ClientSocket.LocalEndPoint).Address;
Random rnd = new Random();
int FstPortNmbr = rnd.Next(5,15);
int SndPortNmbr = rnd.Next(0,999);
string localAddressCom = localAddress.ToString().Replace(".",",")+","+FstPortNmbr.ToString()+","+SndPortNmbr.ToString();
int portPort = FstPortNmbr*256+SndPortNmbr;
string command = "PORT "+localAddressCom;
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);
PasvPortSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPHostEntry iphost = Dns.GetHostByName(RemoteHost);
ip = iphost.AddressList[0];
PasvPortSocket.Connect(new IPEndPoint(ip,portPort));
 
RemoteHost - адрес ftp соответственно.
Выбрасывает с ошибкой "No connection could be made because the target machine actively refused it". Вроде нигде не напортачил, ан вот как. Да, и исходников с FTP клиентами работающих на PORT mode я не нашёл ... неспроста это всё, неспроста ...

Всего записей: 77 | Зарегистр. 17-03-2003 | Отправлено: 23:54 10-05-2003
v0yager



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
при работе в PORT mode для создания канала данных не ты соединяешься с фтп-сервером, а он с тобой (см. еще раз All About FTP
 
а в примере, который ты привел, смешаны воедино PORT & PASV режимы.
 
до отправки команды

Код:
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);  

тебе нужно открыть Listener на выбранный EndPoint. Тоесть, сначала открываешь Listener, а потом командой PORT сообщаешь серверу на каком адресе/порте ты его ждешь. Само собой, что должна быть техническая возможность установить соединение по данному адресу/порту от фтп-сервера.
 
Учти также, что выбранный рандомом порт уже может быть занят другим клиентским приложением: если получил исключение - исчешь дальше.
 
в примере же идет попытка установить соединение со стороны клиента по рандом-порту (который клиент сам и сгенерировал) и адресу сервера. Разумеется, сервер это предложение не принимает.
 
Ты уверен, что тебе нужен именно PORT mode?

Всего записей: 95 | Зарегистр. 08-05-2003 | Отправлено: 10:50 11-05-2003
AndrewWork

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Угу, именно PORT mode. По PASV у меня клиент уже коннектить.

Всего записей: 77 | Зарегистр. 17-03-2003 | Отправлено: 14:39 11-05-2003
v0yager



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
тогда обрати внимание, на то что я уже написал в предыдущем посте.
 
Вместо
Код:
PasvPortSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
IPHostEntry iphost = Dns.GetHostByName(RemoteHost);  
ip = iphost.AddressList[0];  
PasvPortSocket.Connect(new IPEndPoint(ip,portPort));

создавай Listener. А то порт рандомом выбираешь сам (нормально для port mode), а потом пробуешь соединиться по этому порту с сервером (как в pasv mode). Разумеется, сервер никого там не ждет, отсюда и ошибка.
 
Упрощенная схема в PORT mode:
 
Выбрал свободный порт, запустил на нем Listener, сообщил об этом серверу командой PORT. Принял соединение от сервера. Дальше как и в PASV mode. Канал управления для команд, канал данных.
 

Всего записей: 95 | Зарегистр. 08-05-2003 | Отправлено: 15:16 11-05-2003
AndrewWork

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Я пытаюсь, чесслово.
 
IPAddress localAddress = ((IPEndPoint)ClientSocket.LocalEndPoint).Address;
Random rnd = new Random();
int FstPortNmbr = rnd.Next(5,15);
int SndPortNmbr = rnd.Next(0,999);
string localAddressCom = localAddress.ToString().Replace(".",",")+","+FstPortNmbr.ToString()+","+SndPortNmbr.ToString();
int portPort = FstPortNmbr*256+SndPortNmbr; // Выбрал свободный порт
string command = "PORT "+localAddressCom;
//----------------------------------------------
TcpListener PasvPortListener = new TcpListener(localAddress,portPort);
PasvPortListener.Start(); //запустил на нем Listener
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0); //сообщил об этом серверу командой PORT
PasvPortSocket = PasvPortListener.AcceptSocket(); //Принял соединение от сервера.
 
Вот последняя строчка не проходит дальше.
Честно говоря мне совестно занимать твоё время, из-за своих проблем, может есть какой-нть ftp клиент работающий на PORT mode с исходниками ?

Всего записей: 77 | Зарегистр. 17-03-2003 | Отправлено: 16:41 11-05-2003
rew



Full Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору

Цитата:
Вот последняя строчка не проходит дальше.

всмысле тормозит выполнение программы? так оно скорей всего ждет что кто то подключится. видимо перед этим нужно послать какую нить команду типа "LIST" например...

----------
плох тот error который не мечтает стать general`ом

Всего записей: 442 | Зарегистр. 09-09-2001 | Отправлено: 23:34 11-05-2003
AndrewWork

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
LIST проходит по каналу control. По моему это тут непричём (да и эксперимент показал). Тут похоже дело просто в технике ... думается мне я не правильно принимаю соединение сервера.

Всего записей: 77 | Зарегистр. 17-03-2003 | Отправлено: 00:43 12-05-2003
rew



Full Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
что бы ждать что то на канале данных  (я хоть почти с c# не знаком но PasvPortListener.AcceptSocket() это вроде как ты ждешь соединения на выбранном порту)нужно что нибудь запросить у сервера, после команды лист сервер должен послать через канал данных список файлов, а по командному каналу возвращает ответ, удалась ли передача или нет
 
Добавлено
AndrewWork
кста после того как шлешь команду, нужно вроде получить ответ сервера
 
Добавлено
кста забывать про
Цитата:
Учти также, что выбранный рандомом порт уже может быть занят другим клиентским приложением: если получил исключение - исчешь дальше.
тоже не стоит


----------
плох тот error который не мечтает стать general`ом

Всего записей: 442 | Зарегистр. 09-09-2001 | Отправлено: 00:48 12-05-2003
AndrewWork

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Ok, я делаю так :  
IPAddress localAddress = ((IPEndPoint)ClientSocket.LocalEndPoint).Address;
Random rnd = new Random();
int FstPortNmbr = rnd.Next(5,15);
int SndPortNmbr = rnd.Next(0,999);
string localAddressCom = localAddress.ToString().Replace(".",",")+","+FstPortNmbr.ToString()+","+SndPortNmbr.ToString();
int portPort = FstPortNmbr*256+SndPortNmbr;
string command = "PORT "+localAddressCom;
command = "LIST \r\n";
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);
Response(); // Получаю ответ "150 Opening ASCII mode data connection for /bin/ls."
TcpListener PasvPortListener = new TcpListener(localAddress,portPort);
PasvPortListener.Start();
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);
PasvPortSocket = PasvPortListener.AcceptSocket();
На последней строчке всё так же зависает ... ждёт коннекта с сервера ...

Всего записей: 77 | Зарегистр. 17-03-2003 | Отправлено: 01:03 12-05-2003
rew



Full Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору

ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);  
command = "LIST \r\n";  
Response(); // Получаю ответ "150 Opening ASCII mode data connection for /bin/ls."  
TcpListener PasvPortListener = new TcpListener(localAddress,portPort);  
PasvPortListener.Start();  
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);  
PasvPortSocket = PasvPortListener.AcceptSocket();  
 
 
Добавлено
всмысле ты 2 раза слал LIST

----------
плох тот error который не мечтает стать general`ом

Всего записей: 442 | Зарегистр. 09-09-2001 | Отправлено: 01:06 12-05-2003
AndrewWork

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Нет, я ошибся в копировании строк сюда. Сначала я отсылаю  
string command = "PORT "+localAddressCom;
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);  
потом команду LIST
command = "LIST \r\n";  
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);  
Затем слухаю сервер ... и похоже не слышу

Всего записей: 77 | Зарегистр. 17-03-2003 | Отправлено: 01:27 12-05-2003
rew



Full Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
может int portPort = FstPortNmbr*256+SndPortNmbr; нужно наоборот? я не помню точно но попробуй int portPort = FstPortNmbr+SndPortNmbr*256;  
кроме того, может это не кртично (хз, но хуже не будет), но всегда получай ответ:
string command = "PORT "+localAddressCom;  
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);  
Response();
...  
command = "LIST \r\n";  
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);  
Response();
 
 
Добавлено
после "string command = "PORT "+localAddressCom;  
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0); "
получил ответ "200 PORT command OK"?

Всего записей: 442 | Зарегистр. 09-09-2001 | Отправлено: 01:35 12-05-2003
AndrewWork

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Нужно именно portPort = FstPortNmbr*256+SndPortNmbr. Так написано и в MSDN и в rfc.
Команды "200 PORT command OK" в ответ не получаю. Странно это кстати ... вообще после  
string command = "PORT "+localAddressCom;  
ClientSocket.Send(Encoding.ASCII.GetBytes(command), command.Length, 0);  
Response(); ничего не получает ...

Всего записей: 77 | Зарегистр. 17-03-2003 | Отправлено: 01:54 12-05-2003
rew



Full Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
AndrewWork
наверно ты послал серверу команду установить пассивный(или вот не помню активный?) режим, это всмысле когда он ждет что ты подключишся к нему, а не он к тебе. я когда разбирался с фтп клиентом (на жаве правда) последовательность команд была следущая
1 "USER "+username
принять ответ типа "331 Password required"
2 "PASS "+pass
принять ответ (тут как правило "заставка" на много строк) типа "230 Logged in, proceed"
3 "TYPE I"
принять ответ типа "200 Type: I"
4 "pwd"
принять ответ типа "257 "/""
5 "TYPE A"
принять ответ типа "200 Type: A N"
6 "PORT "+...
принять ответ типа "200 PORT command OK"
7 "LIST"
принять ответ типа "150 Opening data connection"
слушать порт
получить данные через полученый сокет
закрыть сокет данных
принять ответ типа "226 Transfer completed"

Всего записей: 442 | Зарегистр. 09-09-2001 | Отправлено: 02:13 12-05-2003 | Исправлено: rew, 02:17 12-05-2003
v0yager



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
AndrewWork

Цитата:
 
int SndPortNmbr = rnd.Next(0,999);
 

 
в команде PORT h1,h2,h3,h4,p1,p2
 
h1-h4, p1-p2 это байты! (0-255) О чем думает сервер, получив в младшем байте номера порта значение до 999 можно только догадываться
 
На твоей машине работают другие клиенты в PORT mode? Если да, то посмотри лог их работы (порядок команд и ответов) и сравни с тем, что делаешь ты.
 
Дополнительно, было бы хорошо поставить один из сетевых мониторов и записать весь траффик при запуске твоего клиента. И, опять же, стравнить с поведением других фтп-клиентов.

Всего записей: 95 | Зарегистр. 08-05-2003 | Отправлено: 09:31 12-05-2003
rew



Full Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
да просто в консоли netstat`ом можно видеть кто по какому порту подключен

Всего записей: 442 | Зарегистр. 09-09-2001 | Отправлено: 10:12 12-05-2003 | Исправлено: rew, 10:12 12-05-2003
Открыть новую тему     Написать ответ в эту тему

Страницы: 1 2

Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » FTP Client на C#


Реклама на форуме Ru.Board.

Powered by Ikonboard "v2.1.7b" © 2000 Ikonboard.com
Modified by Ru.B0ard
© Ru.B0ard 2000-2024

BitCoin: 1NGG1chHtUvrtEqjeerQCKDMUi6S6CG4iC

Рейтинг.ru