Главная » Статьи » Рефераты » Без категории |
Без сетей сейчас никуда, это верно и для программиста и для железячника. Стандартом де-факто в организации современных сетей стал протокол TCP, понимание которого еще на шаг приблизит нас к профессионалам. К тому же, ознакомившись с принципами межсетевого обмена данными и соединив эти знания с нашими познаниями в области межпроцессных взаимодействий мы сможем писать вполне достойные программы. Предполагается, что вы уже имеете некоторые понимание в принципов организации сетей на базе TCP/IP. По крайней мере, вы должны знать что такое доменное имя, IP-адрес и порт. Итак, приступим.
Сокеты бывают нескольких типов: потоковые и датаграммные. Датаграммные сокеты не гарантируют сохранности передаваемых данных. Сокеты этого типа подходят разве что для обмена пользовательским сообщениями, поэтому заострять внимание на них мы не будем. Потоковые сокеты обеспечивают надежный двусторонний обмен данными. Работа с сокетами очень похожа на работу с каналами. Помимо типов, сокеты подразделяются по областям действия: INET и UNIX. Область действия определяет метод идентификации сокета: для интернет-сокетов это адрес хоста и номер порта, а для сокетов UNIX - имя файла. Далее речь пойдет преимущественно о потоковых интернет-сокетах. В случае с каналами мы просто связывали два дескриптора с помощью функции pipe. Таким образом мы получали односторонний канал связи. В случаях, когда нам было необходимо обеспечить двухстороннюю связь нам приходилось напрягаться чуть больше: создавать два канала, переопределять потоки и т.п. Потоковые сокеты обеспечивают двустороннюю связь. То есть, мы можем читать и писать с каждой стороны соединения. Но программирование сокетов несколько усложняется из-за возможности сетевого соединения. В отличии от каналов, сокеты могут создаваться на разных машинах соединенных сетью (поддерживающей протокол TCP/IP). Для того, что бы как то избавиться от неопределенности действий при создании соединения введены такие понятия как сервер и клиент. В контексте этой статьи сервером будем называть процесс, который создает сокет и ожидает подключения клиентов. Клиенты - это те процессы, которые пытаются инициировать соединение с сервером. При этом, не важно на какой машине в сети будет находиться клиент: он может инициировать соединение с сервером на локальной машине или на удаленной. В общем, процесс соединения можно разделить на несколько этапов. Первым делом, необходимо получить идентификатор создаваемого сокета (иначе - имя) независимо от того, клиент это или сервер. Далее, и клиент и сервер должны создать сокет с указанным именем. После этого сервер переходит в режим ожидания входящих подключений, а клиент выполняет попытку подключения к серверу. В случае успешного прохождения этих этапов мы имеем готовое соединение: дескриптор чтения/записи у сервера и аналогичный у клиента. Теперь можно приступать к обмену данными. В процессе разбора принципов межпроцессных взаимодействий мы уже сталкивались с проблемой открытых дескрипторов. Так вот, с сокетами то же самое: не забывайте закрывать дескрипторы. Впрочем, мы наверняка еще столкнемся с этой проблемой, ведь у нас впереди целая куча подводных камней, которую придется разгребать при работе с сокетами.
Для начала разберем простой пример - получение документа по протоколу HTTP. Существует специальный интерфейс облегчающий работу с сокетами из Perl - IO::Socket. Однако, мы не будем использовать IO::Socket, так как мы желаем получить максимальный контроль над соединением. Хотя реально, использование IO::Socket значительно облегчает работу с сокетами, да к тому же значительно снижает риск допустить ошибку. При решении реальных задач я рекомендую использовать IO::Socket. Итак, я назвал программу "gethttp.pl". Нам понадобится модуль Socket, в котором реализованы все необходимые платформозависимые функции. Прежде всего, это касается функции идентификации сокетов. Но, все по порядку. #!/usr/bin/perl -w # gethttp.pl use Socket; unless ($#ARGV == 1){ } my $sock_name = GetSockName($ARGV[0],80) or die "Couldn't convert $ARGV[0] into an Internet address: $!\n"; connect(CONN,$sock_name) or die "Couldn't' connect to $ARGV[0]: $!\n"; print CONN "GET $ARGV[1] HTTP/1.0\n"; print CONN "Host: $ARGV[0]\n\n"; my @body = <CONN>; После подключения модуля Socket мы проверяем достаточно ли аргументов передано на вход программы. Согласно описанию, запуск программы должен аргументироваться двумя значениями: именем хоста и виртуальным путем получаемого документа. Так вот, если массив входных аргументов не содержит необходимых двух аргументов, тогда программа завершается.
sub GetSockName{ my ($nm,$pt) = @_; } Теперь давайте попробуем, что же у нас получилось. Запускаем программу и... Ха-ха-ха. Что, опять зависли? Ну и где же у нас ошибка? Правильно, мы забыли отключить буфферизацию. Данные как бы отправлены, но их слишком мало для заполнения буффера. Поэтому фактически, наши отправленные данные застряли в сокете. А сервер ждет и ждет, когда же клиент заявит о своем желании. Давайте исправим положение и добавим следующий код между строк: connect(CONN,$sock_name) or die "Couldn't' connect to $ARGV[0]: $!\n"; print CONN "GET $ARGV[1] HTTP/1.0\n"; Вот теперь все должно работать.
Наша программа, конечно, не супер-пупер, но на кое-что она все-таки сгодится. Например, если отделить заголовки ответа от, непосредственно, тела ответа, то можно скачивать файлы по HTTP. Давайте так и сделаем. Как нам известно, ответ сервера состоит из заголовка и тела. При чем, заголовок ответа отделяется от тела двумя переводами строки. Вот и найдем эти два перевода строки: print CONN "GET $ARGV[1] HTTP/1.0\n"; print CONN "Host: $ARGV[0]\n\n"; my $body = ""; $body .= $_ while <CONN>; print $body; Теперь мы можем выполнить команду: для получения HTML-кода индексной страницы нашего сайта. Ну и все, для начала. У вас уже достаточно навыков для возни с протоколами высокого уровня. Вот и попробуйте поработать с FTP, или SMTP. | |
Просмотров: 227 | |
Всего комментариев: 0 | |