在PHP中使用Sockets 从Usenet中获取文件


Posted in PHP onJanuary 10, 2008

作者:Armel Fauveau 
原文地址:http://www.phpbuilder.net/columns/armel20010427.php3
PHP能够打开远程或者本地服务器的sockets!这里是一个使用socket的简单的例子:连接到Usenet的新闻服务器,与服务器沟通,并从一个精确的新闻分组中下载一些文章。

使用PHP打开Socket
使用fsockopen()来打开一个Socket。这个函数在PHP3和PHP4中都存在。函数的原型如下:
<?php

intfsockopen 
    (string hostname, 
        int port [, 
        int errno [, 
        string errstr [, 
        double timeout]]])
?>
对于网络主机,它将建立一个TCP的Socket的连接到主机名的端口上。主机名可以是域名或者IP地址。对于UDP连接,你需要明确指出其协议:udp://hostname。对于unix主机,主机名将在socket的路径中使用,在这个例子中端口必须设置成0。可选项timeout可以用来设置连接超时的秒数。
关于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;
// open asocket
if(!$cfgTimeOut)
    // without timeout
    $usenet_handle = fsockopen($cfgServer, $cfgPort);
else
    // with timeout
    $usenet_handle = fsockopen($cfgServer, $cfgPort, &$errno, &$errstr, $cfgTimeOut);
if(!$usenet_handle) {
    echo"Connexionfailed\n";
    exit();
}    
else {
    echo"Connected\n";
    $tmp = fgets($usenet_handle, 1024);
}
?>

与服务器交互
现在我们已经连接上服务器了,而且能够通过先前打开的socket连接与服务器进行交互。让我们对服务器说“我们要从某一新闻分组中获取到最新的10篇文章”。RFC977定义了如何选择正确的新闻分组的命令,如下:
GROUPggg
必需的参数ggg是你将要选择的新闻分组的名字,比如net.news。使用list命令你可以获取到一组有效的新闻列表。成功选择响应会返回组中首尾两篇新闻的新闻号以及对存档新闻号估计。
比如

chrome:~$ telnetmy.news.host 119
Trying aa.bb.cc.dd...
Connected tomy.news.host.
Escape character is'^]'.
200 my.news.hostInterNetNews NNRP server INN 2.2.2 13-Dec-1999 ready (posting ok).
GROUP alt.test
211 232 222996 223235alt.test
quit
205 .
在接受到命令“GROUP alt.test”,新闻服务器返回了“211232 222996 223235 alt.test”。其中211是RFC标识码(简单的解释说命令已经成功的执行—查看RFC你可以获取更加详细的资料),返回信息说明其中有232篇文章,其中最旧的新闻的索引号是222996,而最新的新闻索引号是223235。现在让我们计算下:222996+232并不等于232235。这丢失的文章或者从这服务器移除出去了,或者被他的作者取消了(是的,这是可能的,也是很容易实现的),或者是删除了。
小心起见,在选择新闻分组之前,服务器可能需要认证,当然这是由服务器是否公开或者私有来决定的。一般是允许任何人获取新闻,但发表新闻需要通过认证。
<?php
//$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 != "281Ok\r\n") {
        echo "502Authentication error\n";
        exit();
    }    
}
// select newsgroup
fputs($usenet_handle, "GROUP ".$cfgNewsGroup."\n");
$tmp = fgets($usenet_handle, 1024);
if($tmp == "480 Authentication required for command\r\n") {
    echo "$tmp\n";
    exit();
}    
$info = split(" ", $tmp);
$first = $info[2];
$last = $info[3];

print "First : $first\n";
print "Last : $last\n";
?>

获取一些文章
现在我们已经有最新文章的A索引号,那就能很容易的获取最新的十篇文章。RFC977指出使用ARTICLE命令可以和文章的索引号或者消息的ID一起使用。为了小心起见,在这里,文章的索引号和消息ID是不同的,因为每个新闻服务器定义不同,所以在不同的新闻服务器上相同文章的索引号都会不一样的,但是消息ID好是唯一的(包含在文章的头部中)
<?php
$cfgLimit    = 10;
// upload last articles
$boucle=$last-$cfgLimit;
while ($boucle <= $last) {
    set_time_limit(0);
    fputs($usenet_handle, "ARTICLE$boucle\n");    
    $article="";
    $tmp = fgets($usenet_handle, 4096);
    if(substr($tmp,0,3) != "220") {
        echo "+----------------------+\n";
        echo "Error onarticle $boucle\n";
        echo "+----------------------+\n";
    }
    else {
        while($tmp!=".\r\n") {
            $tmp = fgets($usenet_handle, 4096);
            $article = $article.$tmp;
        }        
        echo "+----------------------+\n";
        echo "Article$boucle\n";
        echo "+----------------------+\n";
        echo "$article\n";
    }    
    $boucle++;
}
?>
我们仅仅从这个服务器的这个分组上获取了十条最新的新闻。你也可以使用HEAD命令来至获取文章的头部信息,或者使用BODY命令来获取新闻的正文。

关闭连接
使用fclose()函数你就可以结束与NNTP服务器之间的会话,当然你可以些一个新的文件,如下:
<?php
// close connexion
fclose($usenet_handle);
?>
更多关于fclose()的信息,请看:http://www.php.net/manual/function.fclose.php

结论
本文中,我们只说明了在确定的情况下如何打开、使用和关闭一个socket连接:连接上一个NNTP服务器然后从新闻分组中取回一些文章。使用POST命令在NNTP服务器上发表一篇文章并不复杂多少。
因此,下一步就是编写一个新闻客户端(并去掉一些Netscape),它需要能很容易的保存文章,并使用一些搜索引擎(比如htgid, http://www.htdig.org/)来索引这些文章,而且要有一个WEB应用程序能进行新闻分组下的关键字搜索。这里有一个例子,你可以访问http://www.phpindex.com/ng/去下载。

PHP 相关文章推荐
dedecms模板标签代码官方参考
Mar 17 PHP
同台服务器使用缓存APC效率高于Memcached的演示代码
Feb 16 PHP
PHP中获取变量的变量名的一段代码的bug分析
Jul 07 PHP
PHP fgetcsv 定义和用法(附windows与linux下兼容问题)
May 29 PHP
PHP 清空varnish 缓存的详解(包括指定站点下的)
Jun 20 PHP
php截取中文字符串不乱码的方法
Dec 25 PHP
php stripslashes和addslashes的区别
Feb 03 PHP
PHP5.6新增加的可变函数参数用法分析
Aug 25 PHP
yii2 url重写并隐藏index.php方法
Dec 10 PHP
YII2.0框架行为(Behavior)深入详解
Jul 26 PHP
PHP用swoole+websocket和redis实现web一对一聊天
Nov 05 PHP
PHP与Web页面交互操作实例分析
Jun 02 PHP
php扩展ZF――Validate扩展
Jan 10 #PHP
set_include_path在win和linux下的区别
Jan 10 #PHP
php模板之Phpbean的目录结构
Jan 10 #PHP
Phpbean路由转发的php代码
Jan 10 #PHP
php框架Phpbean说明
Jan 10 #PHP
深入解析php模板技术原理【一】
Jan 10 #PHP
php下MYSQL limit的优化
Jan 10 #PHP
You might like
PHP也可以?成Shell Script
2006/10/09 PHP
PHP session有效期session.gc_maxlifetime
2011/04/20 PHP
ThinkPHP实现动态包含文件的方法
2014/11/29 PHP
php+mysql实现用户注册登陆的方法
2015/01/03 PHP
PHP yii实现model添加默认值的方法(两种方法)
2016/11/10 PHP
PHP守护进程化在C和PHP环境下的实现
2017/11/21 PHP
解决在laravel中auth建立时候遇到的问题
2019/10/15 PHP
Thinkphp 框架扩展之应用模式实现方法分析
2020/04/27 PHP
Javascript 个人笔记(没有整理,很乱)
2007/07/07 Javascript
使用JavaScript进行进制转换将字符串转换为十进制
2014/09/21 Javascript
JavaScript中的pow()方法使用详解
2015/06/15 Javascript
基于Bootstrap实现的下拉菜单手机端不能选择菜单项的原因附解决办法
2016/07/22 Javascript
vue.js入门教程之绑定class和style样式
2016/09/02 Javascript
详解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 构建记事本应用
2017/06/16 Javascript
小程序api实现promise封装过程解析
2019/11/21 Javascript
JavaScript基于SVG的图片切换效果实例代码
2020/12/15 Javascript
编写同时兼容Python2.x与Python3.x版本的代码的几个示例
2015/03/30 Python
python排序方法实例分析
2015/04/30 Python
Python3字符串学习教程
2015/08/20 Python
python对配置文件.ini进行增删改查操作的方法示例
2017/07/28 Python
centos 安装python3.6环境并配置虚拟环境的详细教程
2018/02/22 Python
Python爬虫框架Scrapy常用命令总结
2018/07/26 Python
python实现flappy bird小游戏
2018/12/24 Python
python3的UnicodeDecodeError解决方法
2019/12/20 Python
python使用正则来处理各种匹配问题
2019/12/22 Python
CSS3改变浏览器滚动条样式
2019/01/04 HTML / CSS
HTML5新增的Css选择器、伪类介绍
2013/08/07 HTML / CSS
美国宠物商店:Wag.com
2016/10/25 全球购物
丹麦优惠购物网站:PLUSSHOP
2019/03/24 全球购物
测试时代收集的软件测试面试题
2013/09/25 面试题
毕业自我鉴定范文
2013/11/06 职场文书
心理学专业大学生职业生涯规划范文
2014/02/19 职场文书
求职信内容一般写什么?
2015/03/20 职场文书
六一儿童节致辞稿(3篇)
2019/07/11 职场文书
咖啡厅里的创业计划书
2019/08/21 职场文书
十一月早安语录:把心放轻,人生就是一朵自在的云
2019/11/04 职场文书