Pull to refresh

Comments 87

Идея не нова. Сокет как файловый дескриптор можно использовать в linux в стандартных функциях read/write и в Windows, в ReadFile, WriteFile.
Другое дело, открыть сокет через обращение к open/CreateFile нельзя, но тут нарушается консистентность с файловой системой:
1) имя tcp://host/port даётся какому объекту, виртуальному? повторное чтение вернёт другие данные? т.е. это не URI, как http://… где можно говорить о наличии адреса у определённого постоянного ресурса
2) что насчёт stat, ls? `ls /tcp` вернёт все доступные хосты, а stat — время рождения хоста / открытия сокета на удалённой стороне?
http://ya.ru?text=hello возвращает всегда одни и те же данные? побойтесь бога. :)
что насчёт stat /dev/tty?
ls вернёт пустоту. облом. Хотя, конечно, можно пойти до конца: /tcp/ru/ya

реакция существующих ФС Юникса на стандартные вызовы умеренно консистента и умеренно полна. ничего нового. да хоть бы и новое. стат вернул -1 — бог мой, все умерли.
Да, Дмитрий, стыдно уж, занимаясь операционными системами не знать про 9P. И его наличие в ядре линукса.
Я знаю, но он сложнее, а тащить код из Линукса — проще застрелиться. Да и лицензия…
MIT-овая реализация есть в Inferno и plan9port
Почитал ещё раз спеку 9P. Навскидку не увидел в описании протокола обработки ситуации, когда сервер упал и рестартовал. File id недостаточно — после рестарта идентичный id может выделиться новому файлу, и клиент, который всё ещё его помнит, может обратиться не туда. Это можно закрыть через явное использование TCP, но это уже требование более высокого уровня (TRFS базируется на UDP) и нагружает протокол дополнительным слоем преобразования данных (эффективность).
Я не понял ничего :) Неплохо бы в статье было привести пару use case, где это использовать и как. Почему бы не привести описание протокола в статье? Читать на гитхабе, да еще и на вражеском, без особого форматирования как-то не очень хочется.
Обмен идёт секторами

А какой размер сектора?
Фактически, сам Фантом использует протокол именно как remote disk.

А можно пояснить?
В моем понимании remote disk — это блоковое устройство, общение с которым традиционно осуществляется по протоколу SCSI (который может инкапсулироваться хоть в IP-пакеты, хоть в FibreChannel, хоть в придуманный вами UDP/TCP протокол). Такое блоковое устройство ничего не знает о файлах, путях, атрибутах. А здесь речь идет все-таки об удаленной файловой системе.
Да. Но фантом просто привязывает фиксированный файл в этой ФС к своему дисковому интерфейсу. При этом запросы преобразуются 1:1.

Блоксайз 512, как минимальный из известных мне, при этом можно запрашивать пачку секторов одним трансфёром. Запрос имеет scatter-gather структуру, ответ имеет право быть нарезан на кусочки (в меру ограничений размера UDP пакета).
$ exec 3<>/dev/tcp/google.com/80
$ echo -en "GET / HTTP/1.0\n\n" >&3
$ cat <&3
HTTP/1.0 302 Found
Location: http://www.google.ie/?gws_rd=cr&ei=YuEkV7GAIYmRgAbP4ZboBA
Cache-Control: private
Content-Type: text/html; charset=UTF-8
P3P: CP="This is not a P3P policy! See https://www.google.com/support/accounts/answer/151657?hl=en for more info."
Date: Sat, 30 Apr 2016 16:46:26 GMT
Server: gws
Content-Length: 258
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Set-Cookie: NID=79=HvOpf6lsXXis3fovmnHG_mRShtGaFIGCv_lS8lBdqcbSwAnZ5jPm9fPlznmxTiJMnsIvm7H1xbqrDhLBtizqTLfXMj5YuYj5FX8x3OdFeyDRy1coRn92y66-ANaIrU7u; expires=Sun, 30-Oct-2016 16:46:26 GMT; path=/; domain=.google.com; HttpOnly

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.ie/?gws_rd=cr&ei=YuEkV7GAIYmRgAbP4ZboBA">here</A>.
</BODY></HTML>


Оно?
Ну и для тех, кого пугает bash с его перенаправлениями, есть socat со всеми этими tcp: и tcp-listen:
open( "/dev/tcp/google.com/80") ведь не пройдёт, это ж в шелле зашит симулякр. Или я ошибаюсь?

Ну так есть же connect, в чем смысл менять стандартный набор API на текстовый интерфейс /dev/host/port?

Вопрос «стандартности» не так прост.

Если бы plan9 стал мейнстримом, то мы бы сейчас кривили рожу на «нестандартный» connect.
смысл в том, что тогда все программы Юникса могут работать с сокетами. а не только специально описанные. регулярный интерфейс лучше.

"Все программы Юникса" умеют работать с fd, так что можно отлично пайпить через nc, curl, socat, в конце концов. Разве с этим была какая-то проблема? API чтения и записи унифицированы.

cat header /tcp/weather1.site divider /tcp/weather1.site footer >weather.html
куда fd засовывать?

cat header <(nc weather1.site) divider <(nc weather1.site) footer >weather.html

Вы знаете, мне удивительно, что это надо объяснять, но Юникс — это не шелл.

Мне совершенно непонятно, почему я не могу сделать file/open в произвольной программе и набрать в качестве имени файла ftp://… или http://, потому что задача ОС — виртуализировать реальность и представлять её программам в униформном виде. И когда мне всерьёз говорят — не надо унификации в ядре, лучше мы поддержим сто разных протоколов в тысяче разных программ ручками, я слегка офигеваю.

Зачем?? Ну вот тупо — зачем нужно иметь socket/connect, если всё то же самое можно сделать через open? Я ещё понимаю (и то умеренно) зачем listen/accept — на реально большом потоке входящих парсить строку имени файла дорого (да и так ли дорого, надо посмотреть ещё). Но есть масса тривиальных программ, которые нуждаются в элементарной работе с сетью на уровне палки и верёвки.

Мало того, реализация этого в ядре — 20 строк кода на всё. Ну тупо позвать из open socket и connect, всё. Люди получили бесплатную единообразность.
UFO just landed and posted this here
И пароль к ftp будет знать любая программа (т.к. он вынуждено будет указан в ссылке), а не только root, под которым монтировали.
UFO just landed and posted this here
Для зашифрованного диска пароль указывается при монтировании.

аутентикация должна происходить на уровне ядра, и именно оно должно спрашивать пароль по запросу, если необходимо

Вы не шутите? Ядро из какой-то своей зарытой глубины ядерного вызова должно понять, от какого юзера пришёл запрос, найти его сессию и в ней создать элемент интерфейса, чтобы спросить пароль? Учитывая все сценарии (текстовая консоль, графическая консоль, ssh-терминал)?
UFO just landed and posted this here
Если нужна аутентификация, то все что должно сделать ядро — вернуть запрос на пароль, что с этим будет делать приложение — это уже задача приложения.

Это убьёт унификацию. Например, у меня обычная утилита копирования файлов. Но получила она SSL-ссылку на такой сервер, который требует клиентский сертификат. Так это что, моя утилита должна уметь не только вводить пароль, но и давать возможность выбирать файл сертификата? А может другой сервер захочет пруфов, что я умею готовить кофе? Или авторизацию по отпечаткам пальцев?
в Windows, например, все подобные запросы обрабатываются на уровне explorer.exe

Одно открытие за другим. Теперь explorer.exe предоставляет API для других приложений ))
UFO just landed and posted this here
Хотелка понятная, но для неё надо весь unix вдоль и поперёк перепилить, простым костылём на open не отделаешься.

Я думаю, ближе всего подошёл к этому Windows PowerShell с объектными пайпами.
Объект с именем C:\file1.txt на самом деле не просто строчка, а некий интерфейс, который имеет свойства и методы. Также можно спланировать, чтобы http://xxx/xx имел сходный интерфейс и программы, которые принимают такие объекты через ком. строку, работали через интерфейсы этих объектов (смотрим, реализует IFileStream — давай с него почитаем байты, а если IFileName — назначим имя открываемому в редакторе документу, а если IFileSaveable, то и сохранение обратно разрешено)
UFO just landed and posted this here
Нет, пароль знать не будет, а лишь получит временный метадату от сервиса ключей, которую сможет использовать для установления соединения. Во всяком случае так происходит в plan9.
То есть, прежде чем я выполню vi ftp://server/file, мне надо к этому серверу ввести ключи в определённый сервис. Недалеко ушли от монтирования ))
Ну почему? Произошло обращение к ftp://server/file. С сервера в ядро (или кто там обрабатывает вызов open) вернулся запрос на логин. Ядро запросило логин у сервиса ключей. Сервис ключей нашёл у себя – отдал / не нашёл у себя – выдал окошко или текстовое приглашение пользователю – отдал.

Принципиальной проблемы тут нет.
А если из cron запущено, в чьей сессии появится окошко?
Ни в чьей не появится, ошибка аутентификации вернётся. Точно так же, как если вызвать ftp из крона.
В Windows есть объекты WindowStation и набор Desktop-ов в ней, в linux это есть на уровне оси или только на уровне графических оболочек?
Да, кстати у такого подхода есть большой минус по сравнению с тем же wget: невозможно скачать с одного сервера с разными аутентификационными данными.

wget запустил параллельно с разными ключами логина/пароля, и качай.
тут же — зарегистрировал в сервисе пароль к серверу, сделал cp /dev/ftp/... myfile, разрегистрировал пароль, зарегистрировал новый пароль… Короче, костыль, как глобальные переменные в программировании.
cp user@ftp:…

Никто не мешает иметь несколько таких ссылок с разными пользователями активными одновременно.
так всё-таки user@ftp://server или /dev/ftp/server/…
В unix это предмет первостепенной важности.
Корень обслуживает один код, по мере движения вниз подключается код из FS.
А тут предлагается поломать эту схему.
Ну в статье, вроде, Фантом обсуждается, а не юникс.
? Это детали. Очевидно, что втыкать в Юникс новую структуру именования файлов — некоторый избыточный авангард.

mount -t tcpfs /tcp
Вопрос в том, с какой стороны к имени файла приклеить юзер/пароль/другие-аутентификационные-данные
Я думаю, тут загвоздка в параметрах, с которыми можно открывать сокет.
В сравнении nc vs /dev/tcp выигрывает nc, которому можно передать кучу опций.
Ну вот передам я ссылку «произвольной программе». В какой кодировке эта программа читать файл будет? Наверное, в системной… А в какой этот файл записан? В любой, сама кодировка приведена в заголовке Content-Type.

Так что, ядро теперь должно еще и перекодированием из windows-1251 в utf-8 заниматься?

Вот сижу и пытаюсь вспомнить, когда бы мне вдруг пригодилась возможность передать http-ссылку «произвольной программе» — и не могу. Ссылки я либо смотрел в браузере (уж эта программа точно должна обрабатывать http сама, кэш там, куки и прочее, что в формат /dev/http/… запихнуть сложно) — либо скачивал. Но та программа, которой надо открывать загруженный файл, определяется либо по заголовку Content-Type — либо по заголовку расширению, которое идет в заголовке Content-Disposition — то есть пока файл не скачаешь, с ним не понятно что делать.

Наконец, файл может быть большой — и лучше его скачать сразу, чем наблюдать как программа «тупит» при его чтении.

Вот и остается единственным сценарием, когда такой способ открытия файла применим — автоматизация, то есть тот самый шелл. В котором уже есть альтернативные механизмы.
Использование любых кодировок, кроме utf-8 – на сегодняшний день рудимент прошлого, и, как таковой, имеет значение только для специальных программ в специальных случаях.
Этот «рудимент» живее всех живых, и будет жить до тех пор, пока в книжках «изучаем PHP за день» не начнут писать про то, как переключить в тестовом редакторе кодировку.

Ну или пока виндовый Блокнот не начнет сохранять в UTF-8 по умолчанию.
Вопрос же не в том, чтобы в командной строке разбирать страницы сайтов из книжки “изучаем PHP за день”, которые, кстати, чуть менее, чем полностью состоят из ссылок на розовенькие гифчики и таблицы стилей. А в том, чтобы просто подцеплять содержимое обычных текстовых файлов, используя протокол http.
>В какой кодировке эта программа читать файл будет? Наверное, в системной…

Насколько я знаю, в Plan9 сервис предоставляющий интерфейс к http протоколу декодирует данные в системную (там юникод) кодировку используя этот заголовок.
А что делать, если программа ожидает файл (т.е. возможность делать seek без каких-либо значимых затрат), а http-сервер на той стороне не поддерживает заголовок range (например, там PHP-скрипт, который пишет в stdout). Plan9 при каждом seek начинает читать файл каждый раз сначала или копирует в кеш и отдаёт байты оттуда? А если приложение захочет записать файл, но предварительно оригинал переименовать в *.bak, какой http-запрос сделает Plan9?
Так не, скачивание файлов не исчезает полностью, ты все так же можешь их скачивать и работать с ними, конечно же. Просто кроме этого появляется множество других способов работы с удаленными ресурсами, которые значительно упрощают многие кейсы.

Вобще прикол плана не в этом, а в том, что можно делать сервисы которые предоставляют единый файловый интерфейс. И его удобство конечно зависит от того, как это смог сделать автор конкретного сервиса. А если на той стороне тупой php-скрипт, то что уж, с ним придется считаться, магии тут никакой нет.
Считаться с тупым скриптом кому? Если в linux это проблема только wget, то в Plan9 каждое приложение должно это учитывать?
Я вот часто сомневаюсь, после таких вопросов, хабр это сайт для айтишников или домохозяек.
Мне вот куда чаще приходится с архивами работать. Давайте архиватор-разархиватор в ядро засунем? Чтобы можно было к архивам как к директориям обращаться! И чтобы поддерживал форматы zip, 7z, rar и cab. И про кодировку имен файлов не забыть…
Почему как архивы — так сразу FUSE, а как tcp или http — так в ядро?
Ну так и TCP можно через FUSE.
Ну так автор статьи-то в ядро засунуть его готов
Это вопрос технический. Конечно, ядро Линукса уже распухло до неприличия и сервисы из него надо выносить мешками.
Это, как уже написали ниже, требует много кода в сисколлах. В Плане действительно можно делать file/open на все, но не он реализует специфичную логику, а сервис, предоставивший к ресурсу файловый интерфейс.
Больше месяца прошло, а AXFR на вашем DNS так и не закрыли. А я уже даже ваших админов нашел и написал им лично. Видимо, до таких «мелочей» руки тоже не доходят =)
Отлично ложится на идею трансляторов GNU Hurd :).
Есть ещё одна вещь, которой нет в современном Юниксе

Для этого nc не подойдёт?

На одном компьютере можно запустить:
$ nc -l host port > local_file

На другом:
$ nc host port < local_file
тогда почему cat >/dev/tty, а не cat | devttydriver?
UFO just landed and posted this here
>Что будет происходит с «cat /tcp/host/port» при нескольких клиентах? Ведь в общем случае в char или block девайс, на который натравливается cat, могут писать больше одной программы.

Каждый будет читать из свого /tcp/host/port.

>Ведь в общем случае в char или block девайс

В общем случае эта разница пришла к нам из 70х, и в наше время такое легаси ненужно.
UFO just landed and posted this here
>Попробуй рандомно прочитать что то с магнитной ленты, tty, да того же IP потока? :) только последовательно.

Логично. Я точно помню что в плане было что-то сделано для унификации и избавления от множества устройств, но сходу не нагуглил.
Не помешала бы ссылка на статью с описанием «что такое Фантом». Я-то нашёл, но если бы первое упоминание «Фантома» было ссылкой, было бы проще.
логично, постараюсь не забывать
С каки это пор socat стал частью ядра?
а зачем оно в ядре? я так и не понял этого ни из статьи, ни из комментариев )

для частных задач «перекачать файл через tcp на другую машину» есть прикладные утилиты вроде nc или socat.

для другого класса задач есть множество сетевых fs.

какую задачу решаем?
Очень странная идея — соединить вместе универсальный транспортный протокол и универсальную концепцию иерархической файловой системы. Результат получится совершенно неуниверсальным. Такое скрещивание обычно делается на уровне приложения, когда уже известна конкретная прикладная задача. Причём между ними ещё вкорячивается какое-то специфичное внутреннее представление, которое с одной стороны хорошо отображается на файловую иерархию, а с другой — с минимальными издержками может быть преобразовано в форму, пригодную для транспортировки. Зачем такое делать в ОС? А если и делать, то почему только это? Почему бы ещё не сделать в ядре тривиальную БД? Я бы не отказался иметь возможность делать «cat /sql/Northwind/Customers | grep Moscow».
Тут хорошо бы не смешивать интерфейс ОС, которым является не шелл, а слой системных вызовов, и реализацию ОС. Которая склоняет к тому, чтобы всё пихать в ядро.

Сам по себе POSIX устарел жутко — нормальным современным интерфейсом для прикладной программы, конечно, давно служит Java class lib (ну или менее богатые, но всё равно объектные интерфейсы иных ЯП), но там, где POSIX вполне применим — для доступа к байт стримам — не применять его странно. В этом смысле для работы с БД он подходит фигово, хотя, с другой стороны, выдать таблицу как входной поток для awk — почему нет.

tcp же реально активно применяется в скриптинге. актуально.

Если TCP активно применяется в скриптинге, то это ещё не повод делать так, чтобы стандартные системные вызовы прозрачно работали с TCP-потоками как с файлами. Нужно просто сделать специальный шелл для TCP-скриптинга или специальную команду для скриптинга в стандартном шелле. Так же, как сделано, например, в DB2. Есть одна команда — db2, которая позволяет работать с сервером из командной строки. Можно писать в шелле почти на чистом SQL:

db2 select * from Customers where City = 'Moscow';

(Любители чистоты могут даже сделать алиасы типа: alias select=db2 select)

Идея мне кажется странной не потому, что это неактуально. Просто я думаю, что при всей актуальности так всё равно не надо делать. Высокоуровневые прикладные задачи нужно решать на более высоком уровне, чем API операционной системы. На уровне API пусть решаются только низкоуровневые задачи. Такой подход предотвратит постепенное превращение ОС в сервер приложений а-ля Tomcat.
во, очень здравый комментарий. стандартизация на уровне ядра работы с сокетами как с файлами в итоге неизбежно приведет к запихиванию в ядро одной из существующих сетевых fs (или к изобретению новой). а зачем — таки-непонятно.
Это уже давно реализовано «IBM System, AS/400»
Sign up to leave a comment.

Articles