php может открывать сокеты на локальной или удаленной машине. В данной статье будет рассмотрен пример использования сокетов для: соединения с usenet-новостным сервером, ведения диалога с ним и скачивания некоторых статей.
Открываем сокет.
Для открывания сокета используется функция fsockopen(). Эта функция доступна, как в php3, так и php4. Вызов функции имеет следующий вид: int fsockopen (string hostname, int port [, int errno [, string errstr [, double timeout]]])
Для udp соединения, надо определить протокол: udp://hostname. Больше информации о функции fsockopen() можно узнав здесь: http://www.php.net/manual/function.fsockopen.php
nntp-протокол (network news transfer protocol)
Для доступа к новостному usenet-серверу мы будем использовать nntp-протокол. Этот протокол детально описан в rfc977 (request for comment number 977). Полное описание присутствует в Интернете: http://www.w3.org/protocols/rfc977/rfc977.html Этот документ детально описывает процедуру соединения и диалога с сервером.
Соединение (connecting)
Для соединения с nntp-сервером нам необходимо знать его имя (или ip-адрес) и порт. Так же необходимо указывать таймер, чтобы в случае невозможности подсоединения к серверу не “заморозили” application.
$cfgserver = "your.news.host"; $cfgport = 119; $cfgtimeout = 10;
// open a socket if(!$cfgtimeout) // without timeout $usenet_handle = fsockopen($cfgserver, $cfgport); else // with timeout $usenet_handle = fsockopen($cfgserver, $cfgport, &$errno, &$errstr, $cfgtimeout);
if(!$usenet_handle) { echo "connexion failedn"; exit(); } else { echo "connectedn"; $tmp = fgets($usenet_handle, 1024); }
?>
Ведение диалога с сервером.
Итак, теперь мы присоединились к серверу и можем вести диалог с ним, используя ранее открытый сокет. Для примера, попробуем достать десять последних сообщений с какой-либо группы. В rfc977 описано, что первый шаг – выбрать группу с помощью group команды: group ggg Обязательный параметр - ggg - имя группы, которую мы хотим выбрать (например, "net.news"). Список существующих групп может быть получен с помощью команды list. Удачный выбор группы будет подтвержден ответом сервера, где будет сообщаться количество новых, старых статей и общее количество.
chrome:~$ telnet my.news.host 119 trying aa.bb.cc.dd... connected to my.news.host. escape character is '^]'. 200 my.news.host internetnews nnrp server inn 2.2.2 13-dec-1999 ready (posting ok). group alt.test 211 232 222996 223235 alt.test quit 205
После получения команды "group alt.test", новостной сервер ответил "211 232 222996 223235 alt.test". 211 – определенный rfc спецификацией код (говоря обычным языком – 212 – означает, что команда была завершена с положительным результатом – смотрите документацию rfc для более полной характеристики). Следующая цифра – 232 – количество имеющихся в текущий момент новых статей. 222996 – старых. 223235 – всего статей. 232+222996 не равно 223235. Почему? Возможно, недостающие семь статей были каким-либо образом удалены модератором или самим автором.
В зависимости от сервера (public или private) вас могут попросить идентифицироваться. Так же возможно, что идентификация понадобиться только при написании своих сообщений, а чтение может производиться без этого.
//$cfguser = "xxxxxx"; //$cfgpasswd = "yyyyyy"; $cfgnewsgroup = "alt.php";
// identification required on private server if($cfguser) { fputs($usenet_handle, "authinfo user ".$cfguser."n"); $tmp = fgets($usenet_handle, 1024);
fputs($usenet_handle, "authinfo pass ".$cfgpasswd."n"); $tmp = fgets($usenet_handle, 1024);
// check error
if($tmp != "281 okrn") { echo "502 authentication errorn"; exit(); } }
// select newsgroup
fputs($usenet_handle, "group ".$cfgnewsgroup."n"); $tmp = fgets($usenet_handle, 1024);
if($tmp == "480 authentication required for commandrn") { echo "$tmpn"; exit(); }
$info = split(" ", $tmp); $first = $info[2]; $last = $info[3];
print "first : $firstn"; print "last : $lastn"; ?>
Скачивание некоторых статей
Теперь мы имеем номер последней статьи, так что сейчас нам не составит труда скачать десять последних статей. rfc977 спецификация допускает использование комманды article, как с номером статьи, так и message id (Уникальный Номер Сообщения).
Будьте внимательны здесь – номер статьи отличен от message id. Если статья опубликована на нескольких серверах, то она несомненно будет иметь разный номер оба раза, но одинаковый message id. Грубо говоря, номер статьи – присваивается каждый раз по-новому на сервере, и может меняться со временем; message id – у каждой статьи уникальный.
$cfglimit = 10;
// upload last articles
$boucle=$last-$cfglimit;
while ($boucle <= $last) {
set_time_limit(0);
fputs($usenet_handle, "article $bouclen");
$article=""; $tmp = fgets($usenet_handle, 4096); if(substr($tmp,0,3) != "220") { echo "+----------------------+n"; echo "error on article $bouclen"; echo "+----------------------+n"; } else { while($tmp!=".rn") { $tmp = fgets($usenet_handle, 4096); $article = $article.$tmp; }
echo "+----------------------+n"; echo "article $bouclen"; echo "+----------------------+n"; echo "$articlen"; }
$boucle++; }
?>
Так же благодаря команде head возможно получить только header сообщения или же только текст, используя команду body.
Отсоединяемся от сервера
Чтобы закрыть сессию с nntp-сервером, просто закройте сокет используя fclose() (аналагично закрытию файла).
// close connexion
fclose($usenet_handle);
?>
Заключение
Мы только что видели как открыть, использовать и затем закрыть сокет – для соединения с nntp-сервером и получения некоторых статей из новостных групп. Для опубликования сообщения необходимо использовать post комманду.
|