IPB

Здравствуйте, гость ( Вход | Регистрация )

 
Closed TopicStart new topic
> Сокеты и http протокол.
Linux
сообщение Jan 25 2007, 01:28
Сообщение #1


Личное звание
Иконка группы

Группа: Admins
Сообщений: 328
Регистрация: 11.6.2006
Пользователь №: 2980



Надеюсь вы уже знакомы с зачатками мирк скриптинга. =)
Итак, чтобы как-то взаимодействовать с сервером нам нужно создать сокет, сгенерировать запрос, получить ответ. Все очень легко=)
Сокет обращается к серверу, а не к странице, или к файлу, который вы хотите скачать. При его создании нужно указать хост или IP сервера и порт, по которому вы соединяетесь с сервером (ибо существуют не только http протокол, да и сервер можно настроить так, что работать он будет не по стандартному http порту)

Итак начнем.

ЧАСТЬ 1.
Открытие сокета и отправка запроса.

Для начала нам нужно как-то обозвать сокет, чтобы отличать его от других, которые возможно будут работать одновременно с ним.=)
Например назовем его test.

%socet = test

Стандартный http порт - (IMG:http://forum.iseekyou.im/style_emoticons/default/mega_shok.gif) й

%port = (IMG:http://forum.iseekyou.im/style_emoticons/default/mega_shok.gif)

Так же нам понадобится сервер, с которым мы соединяемся (запомните, хост пишется без http:// иногда без www, иногда с ним, смотря как сервер настроен)

%host = google.ru

Создаем (открываем) сокет

sockopen %socet %host %port

Итак сокет открыт. Генерируется событие SOCKOPEN.
Обрабатываем его.

on *:SOCKOPEN:test:{

Теперь по плану мы должны сформировать запрос. Он сотоит из строк; в первой мы должны указать, по какому методу будет обрабатываться наш запрос, что мы хотим закачать с сервера, и с какой версией протокола HTTP мы работаем.
Выглядит это так:

METHOD %path HTTP/1.0

Где %path - локальный путь до файла, относительно хоста. Т.е. если полная ссылка до файла или страницы - http://www.google.ru/images/hp1.gif , то соответственно

%path = /images/hp1.gif

Естественно %path надо определять до запроса=)
HTTP 1.0 мы взяли, потому что нам не важно сейчас, какая версия протокола=)
Основных методов два: GET и POST
Различия между ними в том, что в методе GET основным параметром является запрос файла или страницы, и данные скрипту мы можем передавать только в этой строке (для тех кто не до конца понял, это %path)
Соответствено %path может выглядеть так:

/aaa.php?param1=word1¶m2=word2

Скрипт aaa.php обработает param1, значением которого является word1 и param2, значением соответственно является word2
В методе POST данные передаются не через строку запроса, а отдельно (мы это рассмотрим ниже).
1я строка запроса у нас должна соответственно выглядеть примерно так:

GET %path HTTP/1.0

или вместо GET - POST
Остальные строки запроса, это сведения о нас
Выглядят они так
Параметр: Значение В конце должны стоять символы перехода на новую строку ($clrf)
Основной параметр:
Host - хост откуда берем, мы по нему соединялись.
Все остальные параметры необязательные, но все же посмотрим основные (по моему мнению) =)
Referer - место откуда мы якобы пришли=)
Cookie - куки, которые мы якобы получили на этом сайте.
В методе GET последняя строка Параметр: значение, должна оканчиваться на $clrf 2 раза (первод строки, и еще раз перевод строки)
Для метода POST у нас добавляется еще параметр
Content-Length - количество пересылаемых данных в байтах
Content-Length оканчивается на $clrf 2 раза, но потом идут передаваемые данные, в общем виде выглядящие так:
param1=word1¶m2=word2
эти данные должны иметь размер равный указанному в Content-Length =)
Т.е. буквально то же самое что мы передаем в методе GET в 1й строке.
В чем различие?
В методе POST можно передавать большие объемы данных ~300кбайт, если я не ошибаюсь=)
Метод GET работает всегда, можете передавать ссылку кому хотите, скрипт обработает как надо=)

Все параметры запроса (а их много) вы можете посмотреть в
RFC1945 - HTTP/1.0 Specification

Для того, чтобы запрос записать в сокет, будем использовать команду

/sockwrite -n %socet

Запись построчно
-n - Добавление символов перевода строки если их еще нет
Так же можем воспользоваться индетефикатором $sockname - возвращает имя сокета (вместо %socet).
$sockerr - если у нас есть ошибка, > 0. По значению можно узнать, что у нас за ошибка.

ИТОГ 1й ЧАСТИ
Объявляем переменные
%host,%path,%port (думаю справитесь)
Потом открываем сокет

sockopen test %host %port

Посылаем запрос.


on *:SOCKOPEN:test:{
if ($sockerr > 0) { echo -a Error1 | return }
sockwrite -n $sockname GET %path HTTP/1.0
sockwrite -n $sockname Host: %host $str($crlf,2)
}


$str($crlf,2) - 2 раза перевели на следущую строку (закрыли запрос). Способов много, но мне так больше нравится=)

ЧАСТЬ 2
Принимаем данные.
После отправки запроса ждем ответа=)
Ответ состоит из 2х частей:
1) Служебный ответ сервера. После него идет пустая строка
2) То, что мы хотим получить
Служебный ответ состоит из нескольких строк:
1я строка, состоит из версии протокола и кода, который сообщает нам правильно ли мы постучались, а так же состояние файла=)

HTTP/1.0 200

Кодов много, в RFC они есть, а так же во многих местах подробно описаны
Основные
200 - документ есть, все в порядке
404 - всем известный код: Документ не найден.
Здесь внизу можете посмотреть краткую расшифровку кодов (на английском)
Остальными строками сервер сообщает клиенту о себе, а также например тип файла. Но это нам сейчас неважно. Если захотите узнать больше, RFC вас ждет=)
Итак при приеме данных генерируется событие SOCKREAD
За прием данных отвечает команда sockread, при чем она может записывать данные как в обычную переменную, так и в бинарную =)
Примем например все в обычную переменную и запишем в файл. %filename - название файла.


on *:SOCKREAD:test: {
if ($sockerr > 0) { echo -a Error2 | return }
sockread %tmp
write %filename %tmp
%tmp = $null
}


Здесь есть несколько недостатков (если нам нужно просто скачать файл):
1) у нас сохраняется все, включая служебный ответ сервера
2) принятая строка может быть слишком длинная, и функция write выдаст ошибку, и не запишет в файл
3) если мы принимаем не текст, то сохранить так скорей всего не получится
Поэтому избавляемся от них. Порассуждаем
Очевидно мы должны сохранять в бинарную переменную. Убираются недостаток 2 и 3, но надо отделить служебный ответ сервера. тут вспоминаем, что между ним и основным текстом пустые строки, для этого проверяем на длину принимаемой строки. Пока не найдем пустую... Возьмем значение длины строки например 4. Все равно сначала у нас идут строки явно больше 4х символов=)

Объявляем где-нибудь раньше в программе, переменную например %chek = 0


on *:SOCKREAD:test: {
if ($sockerr > 0) { echo -a Error2 | return }
if (%check == 0) {
sockread %tmp
if ($len(%tmp) (IMG:http://forum.iseekyou.im/style_emoticons/default/mega_shok.gif)
%path = /images/hp0.gif
%filename = hp0.gif
.remove %filename
sockopen test %host %port
}
on *:SOCKOPEN:test:{
%check = 0
if ($sockerr > 0) { echo -a Error1 | return }
sockwrite -n $sockname GET %path HTTP/1.0
sockwrite $sockname Host: %host $str($crlf,2)
}

on *:SOCKREAD:test: {
if ($sockerr > 0) { echo -a Error2 | return }
if (%check == 0) {
sockread %tmp
if ($len(%tmp) < 4) { %check = 1 }
}
if (%check == 1) {
sockread &binvar
bwrite %filename -1 -1 &binvar
}
}

on *:SOCKCLOSE:test: {
echo -a Complete!
}


Просто наберите /http_test и проверьте =)
Проверено в mIRC 6.12, ошибок нет, все скачивается нормально
remove - чтобы файл не дописывался в конец существующего, если запустите несколько раз.


Эта статья не претендует на большую правильность. =)
Просто надеюсь, что кому-то помог.
Если заинтересовались, читаете хелп по мирку в разделе сокеты и RFC по http протоколу (а так же по другим ). Я освятил далеко не все возможности
Удачи вам=)
Go to the top of the page
 
+Quote Post

Closed TopicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



Текстовая версия Сейчас: 29th December 2024 - 03:27