Игры с сетевыми котами: изобретем /usr/bin/yes еще раз
 
Автор: (C) Жаовай [zhaoway]
Перевод: (C) Сергей Скороходов


Кошка Нет и и кошка Да [Netcat and Yescat]

Первая (но не главная) задача этой статьи: познакомить вас с прелестной сетевой "тулзой": /usr/bin/netcat, которую можно без труда найти в одноименном пакете Debian GNU/Linux (упражнение: выполните apt-get install netcat -- и готово!). Автор программы, пожелавший остаться неизветстным, снабдил ее хорошо написанной документацией, на основе которой мои коллеги-разработчики Debian сделали прекрасно отформатированную страницу руководства Unix. Читать эту документацию -- одно удовольствие. Благородному читателю наверняка придет в голову, что да, действительно есть такие существа -- UNIX гуру -- живущие где-то там, в Дальнем Мире. И они, исключительно из харерских побуждений, сохраняют анонимность после написания столь превосходного программного обеспечения. Только подлинные гуру Unix'а могут так поступить!

Раз уж документация по netcat так хороша, я ее здесь повторять не буду. Однако, я советую всем прочесть ее, прежде чем приступать к этой статье. Для нетерпеливых же сообщаю: netcat может перенаправлять поток данных из стандартного ввода в TCP или UDP сокет, а из TCP или UDP сокета -- в стандартный вывод. Точно так, как команда cat перенаправляет из стандартного ввода [stdin] в стандартный вывод [stdout]. По непроверенным данным, именно от этой утилиты произошло название программы netcat.

Вторая, но зато основная задача этой статьи -- показать, сколь скучным и невежественным можте быть автор статей (вроде меня) при описании программы без графического интерфейса пользователя или интерактивной справки. Если я типа не могу "заграбастать" хотя бы пары скриншотов -- то я просто шизею!

А теперь, для целей, которые станут понятными далее, мы представим пикантную программку /usr/bin/yes. Почти никто не обращает на нее внимание. А она тихонько лежит там, в уголке /usr/bin уже так давно, что едва ли кто-либо из нас, недавно пришедших в мир Linux, хотя бы подозревает о ее присутствии в системе. Происхождение этой программы покрыто тайной. А популярность у нее -- не меньше, чем у /sbin/init! Что она делает? Давайте посмотрим:

zw@q ~ % yes
y
y
y
y
y
y
y

Ну, разве не чудо? ;-) (Нажмите ctrl-C для того, чтобы остановить поток 'y'-ов, иначе они будут вечно маршировать по экрану.) Между прочем, программа может сказать и нет!

zw@q ~ % yes no
no
no
no
no
no

В последующих разделах мы разработаем две вспомогательные утилиты, с помощью которых мы сделаем свой вариант /usr/bin/yes, естественно с помощью /usr/bin/netcat! В путь!

Hub и cable

Источником вдохновения при создании утилит hub (hub.c) и cable (cable.c), безусловно, явился netcat, пересылающий поток данных от сокета к стандартному выводу и со стандартного входа -- на сокет. Разве я забыл порекомендовать прочесть сопровождающую netcat документацию? ;-) Hub задуман, как сервер, а cable -- как клиент. Вместо того, чтобы перенаправлять данные между stdin, stdout и сокетами, hub и cable направляют и мультиплексируют данные от сокета на другие сокеты. Вот откуда взялись их имена. Они работают, как hub и cable в Ethernet. Взгляните на скриншот. О-о, скриншот! ;-)

zw@q ~ % ./hub
Лаборатория Сетевых Колыбельных: hub (сервер) $Revision: 1.5 $
Copyright (C) 2001  zhaoway <zw@debian.org>

Использование: hub [размер буфера] [номер порта tcp] [число портов в "хабе"]

o размер буфера указывается в байтах. например 10240.
o номер порта tcp должен быть не меньше 1024 для того, чтобы не требовались права root'а.
o в хабе должно быть не менее двух портов. будьте счасливы.
zw@q ~ %

Hub слушает порты TCP также, как работает Ethernet hub. Данные, поступающие с одного порта hub'а, будут направлятся на остальные его порты. С помощью netcat можно протестировать hub не прибегая к cable. Учтите: nc -- это сокращение для netcat.

  1. Запустите hub в консоли. Вот так: ConA % ./hub 10240 10000 2
  2. Из консоли B подсоединитесь netcat'ом: ConB % nc localhost 10000
  3. Из консоли C подключите еще один netcat: ConC % nc localhost 10000
  4. Можете печатать текст в ConC, а читать в ConB и наоборот.

А теперь займемся cable:

zw@q ~ % ./cable
Лаборатория Сетевых Леденцов: cable ( клиент) $Revision: 1.14 $
Copyright (C) 2001  zhaoway <zw@debian.org>

Использовать: cable [размер буфера] [1-й ip] [1-й порт] [2-1 ip] [2-й порт] ...

o размер буфера указывается в байтах. например 10240.
o порты должны прослушиваться, иначе попытка соединения закончится неудачей.
o должно быть указано по меньшей мере два набора ip:port.
zw@q ~ %

Cable работает примерно как разделямый коаксиальный кабель Ethernet. Он перенаправляет и мультиплексирует данные между слушающими демонами сокетов. Давайте испытаем и его.

  1. Запускаем демон netcat в ConA: ConA % nc -l -p 10000
  2. Запускаем другой демон netcat в ConB: ConB % nc -l -p 10001
  3. Организуем cable: ConC % ./cable 10240 127.0.0.1 10000 127.0.0.1 10001
  4. Теперь можно вводить текст в ConA, а читать в ConB и наоборот.

В разработке hub и cable применены любопытные приемы. Особенно советую обратить внимание на вызов функции select(). А пока сосредоточимся на повторном измобретении /usr/bin/yes ;-).

Изобретаем колесо заново

Не так-то просто с помощью netcat, hub и cable изобрести /usr/bin/yes еще раз. Могу намекнуть: поэтому мне и потребовалось устанавливать размер буфера в аргументе командной строки. Тем не менее, приступим!

Основная идея такова. Сначала мы настроем трех-портовый hub, потом соединим два "хаба" с помощью "кабеля", а затем мы сможем использовать netcat для того, чтобы повторять любой символ в свободные порты "хаба". Как на диаграмме:

            |        кабель-cable
           \|/        ,---------,
            |         |         |
            V         V         V
	,--[ ]-------[ ]-------[ ]--.
        |   A         B         C   |
        | трехпортовый хаб-hub      |
	`---------------------------'

Природа hub'а такова, что данные, посылаемые на порт А будут перенаправлены на порты B и C, а так как порты B и C соеденены кабелем, данные, поступившие из "хаба" отправятся равнехонько назад и будут мультеплексированы и направлены в порт А, циркулируя в петле кабеля до бесконечности. В конце концов порт А получит бесконечное число копий изначально введенных данных.

Соберем устройство.

  1. В ConA запускаем трехпортовый "хаб": ConA % ./hub 10240 10000 3
  2. В ConB замыкаем "кабель": ConB % ./cable 10240 127.0.0.1 10000 127.0.0.1 10000

Теперь, когда мы завершили сборочные работы, можно с помощью netcat наконец-то завершить наше повторное изобретение /usr/bin/yes.

ConC % echo "y" | nc localhost 10000
y
y
y
y
y
y

Хитрое упражнение для читателя: что случится, если мы изменим размер буфера (и для hub, и для cable) с 10240 байт до 1 байта? Можете попробовать сами.

Так что не скучайте и удачи!


Жаовай [Zhaoway]

Жаовай живет в Наньдзине, в Китае. Свое время он делит между прелестной подружкой, стареьнким "пнем" и чистой математикой. (Он занимается "высшематематическим самообразованием", так что если у вас завалялось несколько лишних, но драгоценных марок и/или книг по высшей математике, то не стесняйтесь послать ему копию). Еще он на добровольной основе участвует в проекте Debian GNU/Linux.


Copyright (C) 2002, zhaoway.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 74 of Linux Gazette, January 2002

Вернуться на главную страницу