Всем привет! Это будет очень маленькая статья. Наша задача тут: подключиться к локальному серверу FTP (я выбрала FileZilla) и отправить туда чего-нибудь используя (очевидно) FTP протокол.
FTP (File Transfer Protocol) — протокол передачи файлов по сети.
Для работы по FTP нужны двое: FTP-сервер и FTP-клиент.
Сервер обеспечивает доступ по логину и паролю к нужным файлам и, соответственно, показывает пользователю только те файлы и папки, к которым он имеет доступ.
Клиент — программа для FTP-соединения. Основная идея в том, чтобы пользователь мог оперировать файловыми данными на стороне сервера: просматривать, редактировать, копировать, загружать и удалять.
Все логично.
В отличие, скажем, от того же HTTP FTP использует в качестве модели соединения двойное подключение. При этом один канал является управляющим, через который поступают команды серверу и возвращаются его ответы (обычно через TCP-порт 21), а через остальные происходит собственно передача данных, по одному каналу на каждую передачу. Поэтому в рамках одной сессии по протоколу FTP можно передавать одновременно несколько файлов, причём в обоих направлениях.
Если расписать процесс установки соединения и дальнейшей передачи данных по пунктам, то получится примерно следующее:
FTP — соединение по умолчанию происходит через порт 21, если не установлен другой порт.
В данном случае будем использовать класс FTPClient из библиотеки Apache (org.apache.commons.net.ftp.FTPClient). Создаем объект класса, устанавливаем таймаут. Затем мы должны сначала подключиться к серверу с помощью connect, прежде чем что-либо делать (и не забыть отключиться после того, как все сделаем). В connect в качестве первого параметра пишем локальный адрес хоста, вторым аргументом — порт для подключения. Также необходимо проверить код ответа FTP (слишком очевидно, но все же), чтобы убедиться, что соединение было успешным.
Хорошо, мы подключились к серверу. Что дальше? Теперь необходимо пройти авторизацию под именем пользователя, которого мы, собственно, создали для этого. Но перед этим нужно установить для текущего режима подключения к данным значение PASSIVE_LOCAL_DATA_CONNECTION_MODE с помощью команды enterLocalPassiveMode(). Это значит, что все передачи будут происходить между клиентом и сервером, и что сервер находится в пассивном режиме, ожидая подключения клиента для инициализации передачи данных. (например, ACTIVE_LOCAL_DATA_CONNECTION_MODE подразумевает, что инициатором подключения будет выступать сервер).
После в login пишем логин и пароль пользователя. storeFile() сохраняет файл на сервере, используя заданное имя и принимая входные данные из заданного InputStream. У меня была задача периодически писать в определенный файл на сервере, поэтому это выглядит так:
Если же вы хотите скопировать свой файл на сервер целиком, можно сделать так (суть не особо меняется, но вдруг кому-то нужно):
В целом это все, что вам может понадобиться. И, конечно, немного о настройке локального FTP сервера. У меня это, как и писала ранее, FileZilla. Все оставляем по дефолту. Создаем пользователя и присваиваем ему папку на хосте, из которой он может читать/писать/удалять и т.д.
Вот и все. Запускаем и смотрим логи на сервере. И вот чего должны получить:
Удачи!
Итак, капелька теории
FTP (File Transfer Protocol) — протокол передачи файлов по сети.
Для работы по FTP нужны двое: FTP-сервер и FTP-клиент.
Сервер обеспечивает доступ по логину и паролю к нужным файлам и, соответственно, показывает пользователю только те файлы и папки, к которым он имеет доступ.
Клиент — программа для FTP-соединения. Основная идея в том, чтобы пользователь мог оперировать файловыми данными на стороне сервера: просматривать, редактировать, копировать, загружать и удалять.
Все логично.
В отличие, скажем, от того же HTTP FTP использует в качестве модели соединения двойное подключение. При этом один канал является управляющим, через который поступают команды серверу и возвращаются его ответы (обычно через TCP-порт 21), а через остальные происходит собственно передача данных, по одному каналу на каждую передачу. Поэтому в рамках одной сессии по протоколу FTP можно передавать одновременно несколько файлов, причём в обоих направлениях.
Если расписать процесс установки соединения и дальнейшей передачи данных по пунктам, то получится примерно следующее:
- Пользователь активирует клиентское приложение и соединяется с сервером, введя логин и пароль.
- Устанавливается управляющее соединение между соответствующими модулями — интерпретаторами протокола со стороны клиента и сервера.
- Пользователь посредством клиента посылает команды серверу, определяющие различные параметры FTP-соединения (активный или пассивный режим, FTP — порт, вид передачи данных, их тип), а также директивы для действий, которые юзер намерен осуществить (например, удалить, переименовать, закачать файл и т.д.).
- Далее один из участников (к примеру, клиент), являющийся пассивным, становится в режим ожидания открытия соединения на FPT — порт, который задан для передачи информации.
Затем активный участник открывает соединение и начинает передавать данные по предназначенному для этого каналу. - По завершении передачи, это соединение закрывается, но управляющий канал между интерпретаторами остается открытым, вследствие чего пользователь в рамках той же сессии может вновь открыть передачу данных.
FTP — соединение по умолчанию происходит через порт 21, если не установлен другой порт.
Реализация
В данном случае будем использовать класс FTPClient из библиотеки Apache (org.apache.commons.net.ftp.FTPClient). Создаем объект класса, устанавливаем таймаут. Затем мы должны сначала подключиться к серверу с помощью connect, прежде чем что-либо делать (и не забыть отключиться после того, как все сделаем). В connect в качестве первого параметра пишем локальный адрес хоста, вторым аргументом — порт для подключения. Также необходимо проверить код ответа FTP (слишком очевидно, но все же), чтобы убедиться, что соединение было успешным.
import org.apache.commons.net.ftp.FTP
import org.apache.commons.net.ftp.FTPClient
import org.apache.commons.net.ftp.FTPReply
...
val con = FTPClient()
con.connectTimeout = ххх
con.connect("192.168.0.105", 21)
if (FTPReply.isPositiveCompletion(con.replyCode)) {
//все круто
}
Хорошо, мы подключились к серверу. Что дальше? Теперь необходимо пройти авторизацию под именем пользователя, которого мы, собственно, создали для этого. Но перед этим нужно установить для текущего режима подключения к данным значение PASSIVE_LOCAL_DATA_CONNECTION_MODE с помощью команды enterLocalPassiveMode(). Это значит, что все передачи будут происходить между клиентом и сервером, и что сервер находится в пассивном режиме, ожидая подключения клиента для инициализации передачи данных. (например, ACTIVE_LOCAL_DATA_CONNECTION_MODE подразумевает, что инициатором подключения будет выступать сервер).
После в login пишем логин и пароль пользователя. storeFile() сохраняет файл на сервере, используя заданное имя и принимая входные данные из заданного InputStream. У меня была задача периодически писать в определенный файл на сервере, поэтому это выглядит так:
con.enterLocalPassiveMode()
if (con.login("nad", "nad")) { //вводим логин и пароль (да, вот так в открытом виде)
con.setFileType(FTP.BINARY_FILE_TYPE)
val msg = "your_msg"
val msg_bytes: InputStream = ByteArrayInputStream(msg.toByteArray())
val result: Boolean = con.storeFile("/sms.txt", msg_bytes)
msg_bytes.close()
if (result) Log.v("upload result", "succeeded")
con.logout()
con.disconnect()
}
}
catch (ex: IOException) {
ex.printStackTrace()
return Result.failure()
}
Если же вы хотите скопировать свой файл на сервер целиком, можно сделать так (суть не особо меняется, но вдруг кому-то нужно):
val file = File("путь до файла")
val msg_bytes = FileInputStream(file)
В целом это все, что вам может понадобиться. И, конечно, немного о настройке локального FTP сервера. У меня это, как и писала ранее, FileZilla. Все оставляем по дефолту. Создаем пользователя и присваиваем ему папку на хосте, из которой он может читать/писать/удалять и т.д.
Вот и все. Запускаем и смотрим логи на сервере. И вот чего должны получить:
Удачи!
Sazonov
Хм, это всё? Вы показали пару строк кода как использовать готовый класс?
itiswhatitiss Автор
Да. А я что-то грандиозное обещаю в начале статьи? Не понимаю таких претензий.
Новичкам может и это помочь. Вот и все. Моя цель — поделиться тем, что может хоть кому-то как-то помочь.
nochkin
Статья вроде как должна быть интересной и давать новую полезную информацию. А то иначе можно просто перепечатать часть документации ради статьи.
И это не говоря о том, что FTP как протокол сегодня как-то не особо востребован по многим понятным причинам.
itiswhatitiss Автор
К сожалению, не всегда приходится самому выбирать, с чем будешь работать, а с чем нет. Порой про интерес и востребованность (если говорим о заданиях, выдаваемые в том же университете) и говорить нечего. Вот и из этого возникает ситуация, когда никому в необъятном интернете эта тема не нужна (да и тебе, честно сказать, тоже), но нужно как-то с ней разобраться. Так вот пусть и будет товарищам-студентам тут пример.
Sazonov
Так вам тогда стоит собственный блог завести для статей такого уровня. И скормить его поисковикам. Тем более, я уверен что практически всё что вы описали будет а документации и примерах.
На хабре посетителями ожидаются статьи более высокой ценности. Вот, к примеру, из недавнего. Статья уровня хабра: https://habr.com/ru/post/540954/
Но в любом случае это здорово, что девушка увлекается программированием и хочет во всём разобраться.
itiswhatitiss Автор
Существуют статьи разного уровня с разной «полезной нагрузкой» — ограничений на Хабре по этому поводу я не вижу, поэтому высказываться могут все и не обязательно статьями уровня диссертации. Я изначально не претендую на ВАУ статью, поэтому и приписываю в начале, что она маленькая и цель ее довольно узкая. Я не пытаюсь кого-то обмануть заоблачными обещаниями, поэтому и не понимаю, к чему вообще началась вся эта шумиха)
Как новичку в Android, пару месяцев назад мне бы пригодилась подобная «краткая иллюстрация» работы с FTP на Android, поэтому сейчас и решила поделиться. Это я к тому, что если 10ти людям не подходит такой формат, это не значит, что не найдется хоть 1 человек, которому это поможет.
Sazonov
Ограничений, конечно нет. Но в этом и фишка хабра, что за качественный контент люди голосуют. Конкретно про ваш случай — это больше похоже на ответ на stackoverflow. В общем, я не хочу судить ;)
Bronn
Вынужден не согласится. Новичкам такое вялое раскрытие вопроса поможет разве что
информацией о существовании Apache Commons Net.
Вы не обижайтесь, а просто взгляните на их пример из документации, он и то куда более познавателен для начинающих.
И ещё, заголовок и тегами меня просто поставили в тупик.
Наверное корректнее назвать:
«Работа с библиотекой Apache Commons Net на языке Kotlin. Глава первая: FTP клиент».
И теги «kotlin, apache commons net library».
А уж в какой ОС мы работаем Android, Linux с FreeBSD или MacOS c Windows — это уже совсем другая история.
itiswhatitiss Автор
Спасибо за действительно дельный совет и объяснение.