在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 相关文章推荐
编写PHP的安全策略
Oct 09 PHP
php in_array 函数使用说明与in_array需要注意的地方说明
Apr 13 PHP
PHP 命令行工具 shell_exec, exec, passthru, system详细使用介绍
Sep 11 PHP
php获取本地图片文件并生成xml文件输出具体思路
Apr 27 PHP
(PHP实现)只使用++运算实现加法,减法,乘法,除法
Jun 27 PHP
PHP中怎样保持SESSION不过期 原理及方案介绍
Aug 08 PHP
php实现图片添加描边字和马赛克的方法
Dec 10 PHP
Linux下从零开始安装配置Nginx服务器+PHP开发环境
Dec 21 PHP
zend framework中使用memcache的方法
Mar 04 PHP
php通过文件头判断格式的方法
May 28 PHP
详解yii2实现分库分表的方案与思路
Feb 03 PHP
tp5框架无刷新分页实现方法分析
Sep 26 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语法(2)
2006/10/09 PHP
Apache 配置详解(最好的APACHE配置教程)
2010/07/04 PHP
php 连接mysql连接被重置的解决方法
2011/02/15 PHP
php实现utf-8和GB2312编码相互转换函数代码
2013/02/07 PHP
ThinkPHP中的关联模型注意点
2014/06/16 PHP
微信公众号开发之微信公共平台消息回复类实例
2014/11/14 PHP
php获取excel文件数据
2017/04/21 PHP
利用javascript的面向对象的特性实现限制试用期
2011/08/04 Javascript
兼容IE、FireFox、Chrome等浏览器的xml处理函数js代码
2011/11/30 Javascript
JS onmousemove鼠标移动坐标接龙DIV效果实例
2013/12/16 Javascript
JavaScript操作 url 中 search 部分方法函数
2016/06/15 Javascript
概述如何实现一个简单的浏览器端js模块加载器
2016/12/07 Javascript
nodejs+express实现文件上传下载管理网站
2017/03/15 NodeJs
JavaScript中双向数据绑定详解
2017/05/03 Javascript
Vue.js上下滚动加载组件的实例代码
2017/07/17 Javascript
JavaScript实现区块链
2018/03/14 Javascript
vue发送ajax请求详解
2018/10/09 Javascript
vue缓存的keepalive页面刷新数据的方法
2019/04/23 Javascript
[01:04:02]DOTA2-DPC中国联赛 正赛 Elephant vs IG BO3 第二场 1月24日
2021/03/11 DOTA
Python 专题五 列表基础知识(二维list排序、获取下标和处理txt文本实例)
2017/03/20 Python
Python cookbook(数据结构与算法)在字典中将键映射到多个值上的方法
2018/02/18 Python
Python用for循环实现九九乘法表
2018/05/31 Python
Python json模块dumps、loads操作示例
2018/09/06 Python
Python unittest 简单实现参数化的方法
2018/11/30 Python
python通过链接抓取网站详解
2019/11/20 Python
python操作ini类型配置文件的实例教程
2020/10/30 Python
python 模拟登陆163邮箱
2020/12/15 Python
用css3制作纸张效果(外翻卷角)
2013/02/01 HTML / CSS
AmazeUI的JS表单验证框架实战示例分享
2020/08/21 HTML / CSS
菲律宾最大的网上花店和礼品店:PhilFlower.com
2018/02/09 全球购物
美国在线工具商店:Acme Tools
2018/06/26 全球购物
Wiggle美国:英国骑行、跑步、游泳、铁人三项商店
2018/10/27 全球购物
Java基础知识面试要点
2016/07/29 面试题
初中女生自我鉴定
2013/12/19 职场文书
家长给孩子的表扬信
2014/01/17 职场文书
企业法人代表证明书
2015/06/18 职场文书