Автор: Армель Фово
Исходный адрес: http://www.phpbuilder.net/columns/armel20010427.php3.
Переводчик: Сюй Лицянфэйфэн[email protected]
http://www.phpobject.net/блог/
PHP может открывать сокеты удаленных или локальных серверов! Вот простой пример использования сокетов: подключитесь к серверу новостей Usenet, установите связь с сервером и загрузите несколько статей из определенной группы новостей.
Открытый сокет с использованием PHP
Используйте fsockopen(), чтобы открыть сокет. Эта функция существует как в PHP3, так и в PHP4. Прототип функции следующий:
<?php
intfsockopen
(строка имени хоста,
внутренний порт[,
внутри ошибка[,
строка errstr[,
двойной таймаут]]])
?>
Для сетевых хостов он установит соединение TCP Socket с портом имени хоста. Имя хоста может быть доменным именем или IP-адресом. Для UDP-соединений необходимо указать протокол: udp://имя_хоста. Для хостов unix имя хоста будет использоваться в пути к сокету, а порт в этом примере должен быть установлен на 0. Дополнительный тайм-аут можно использовать для установки количества секунд для тайм-аута соединения.
Дополнительную информацию о fsockopen() можно найти по адресу http://www.php.net/manual/function.fsockopen.php.
Протокол передачи сетевых новостей (NNTP)
Доступ к серверу новостей Usenet требует использования специального протокола, называемого NNTP, стандарта протокола передачи сетевых новостей. Подробности этого протокола приведены в RFC977, который вы можете просмотреть по адресу http://www.w3.org/Protocols/rfc977/rfc977.html . В этом документе подробно описывается, как использовать различные команды для подключения и общения с сервером NNTP.
Сервер соединений Для подключения к NNTP-серверу необходимо знать имя хоста сервера (или IP-адрес) и порт, который он будет прослушивать. Также рекомендуется добавить таймаут, чтобы программа не «зависала» при сбое соединения.
<?php
$cfgServer="your.news.host";
$cfgPort =119;
$cfgTimeOut =10;
// открываем сокет
если(!$cfgTimeOut)
// без таймаута
$usenet_handle=fsockopen($cfgServer,$cfgPort);
еще
// с таймаутом
$usenet_handle=fsockopen($cfgServer,$cfgPort, &$errno, &$errstr,$cfgTimeOut);
если(!$usenet_handle) {
echo "Ошибка соединенияn";
Выход();
}
еще {
echo "Подключеноn";
$tmp=fgets($usenet_handle,1024);
}
?>
Взаимодействие с сервером Теперь мы подключены к серверу и можем взаимодействовать с сервером через ранее открытое соединение сокета. Скажем серверу: «Мы хотим получить последние 10 статей из определенной группы новостей». RFC977 определяет команду выбора правильной группы новостей следующим образом:
ГРУППАгггг
Обязательный параметр ggg — это имя группы новостей, которую вы хотите выбрать, например net.news. Используя команду list, вы можете получить действительный список новостей. Успешный ответ выбора вернет номера новостей первой и двух последних новостных статей в группе, а также оценку количества заархивированных новостей.
например
хром:~$ telnetmy.news.host 119
Пробую aa.bb.cc.dd...
Подключен к my.news.host.
Escape-символ: '^]'.
200 my.news.hostInterNetNews Сервер NNRP INN 2.2.2 13 декабря 1999 г. готов (проводка одобрена).
ГРУППА альтернативный тест
211 232 222996 223235альт.тест
покидать
205.
После получения команды «GROUP alt.test» новостной сервер вернул «211232 222996 223235 alt.test». 211 — это идентификационный код RFC (простое объяснение того, что команда была успешно выполнена — для получения более подробной информации проверьте RFC). Возвращенная информация указывает на то, что имеется 232 статьи, среди которых порядковый номер самой старой новости — 222996, а номер — 222996. последний индекс новостей — 223235. Теперь давайте посчитаем: 222996+232 не равно 232235. Недостающая статья была либо удалена с сервера, либо отменена ее автором (да, это возможно и легко сделать), либо удалена.
В качестве меры предосторожности сервер может потребовать аутентификацию перед выбором группы новостей, в зависимости от того, является ли сервер общедоступным или частным. Как правило, получать новости разрешено любому человеку, но публикация новостей требует сертификации.
<?php
//$cfgUser = "xxxxxx";
//$cfgPasswd = "yyyyyy";
$cfgNewsGroup="alt.php";
// требуется идентификация на частном сервере
если ($cfgUser) {
fputs($usenet_handle,"AUTHINFO USER".$cfgUser."n");
$tmp=fgets($usenet_handle,1024);
fputs($usenet_handle,"AUTHINFOPASS".$cfgPasswd."n");
$tmp=fgets($usenet_handle,1024);
//проверяем ошибку
if($tmp!="281Okrn") {
echo "502Ошибка аутентификацииn";
Выход();
}
}
// выбираем группу новостей
fputs($usenet_handle,"GROUP ".$cfgNewsGroup."n");
$tmp=fgets($usenet_handle,1024);
if($tmp=="Для команды требуется аутентификация 480rn") {
эхо "$tmpn";
Выход();
}
$info=split(" ",$tmp);
$first=$info[2];
$last=$info[3];
print"Сначала: $firstn";
print"Последний: $lastn";
?>
Получить несколько статей Теперь, когда у нас есть индексный номер А последней статьи, мы можем легко получить последние десять статей. В RFC977 указано, что команду ARTICLE можно использовать с порядковым номером статьи или идентификатором сообщения. В целях предосторожности здесь порядковый номер статьи и идентификатор сообщения различаются. Поскольку каждый сервер новостей имеет разные определения, порядковый номер одной и той же статьи на разных серверах новостей будет разным, но идентификатор сообщения должен быть разным. уникальный (упомянут в шапке статьи).
<?php
$cfgLimit = 10;
// загружаем последние статьи
$boucle=$last-$cfgLimit;
while ($boucle<=$last) {
set_time_limit (0);
fputs($usenet_handle,"ARTICLE$bouclen");
$статья="";
$tmp=fgets($usenet_handle,4096);
if(substr($tmp,0,3) !="220") {
echo"+----------------------+n";
echo "Ошибка в статье $bouclen";
echo"+----------------------+n";
}
еще {
while($tmp!=".rn") {
$tmp=fgets($usenet_handle,4096);
$article=$article.$tmp;
}
echo"+----------------------+n";
echo "Статья$bouclen";
echo"+----------------------+n";
echo "$статьяn";
}
$букле++;
}
?>
На этом сервере мы получаем только десять последних новостей из этой группы. Вы также можете использовать команду HEAD, чтобы получить информацию о заголовке статьи, или команду BODY, чтобы получить тело новости.
Закройте соединение и используйте функцию fclose(), чтобы завершить сеанс с NNTP-сервером. Конечно, вы можете создать новый файл следующим образом:
<?php
// тесное соединение
fclose($usenet_handle);
?>
Дополнительную информацию о fclose() см. по адресу: http://www.php.net/manual/function.fclose.php.
Заключение В этой статье мы показали, как открывать, использовать и закрывать сокет-соединение только при определенных обстоятельствах: подключиться к NNTP-серверу и получить некоторые статьи из группы новостей. Опубликовать статью на NNTP-сервере с помощью команды POST не намного сложнее.
Итак, следующий шаг — написать новостной клиент (и убрать немного Netscape), который сможет легко сохранять статьи и индексировать их с помощью какой-либо поисковой системы (например, htgid, http://www.htdig.org/), и должна быть WEB-приложение, которое может выполнять поиск по ключевым словам в группах новостей. Вот пример. Вы можете посетить http://www.phpindex.com/ng/ , чтобы загрузить его.