在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 字符串编码截取函数(兼容utf-8和gb2312)
May 02 PHP
深入php函数file_get_contents超时处理的方法详解
Jun 03 PHP
解析php中static,const与define的使用区别
Jun 18 PHP
codeigniter自带数据库类使用方法说明
Mar 25 PHP
浅析application/x-www-form-urlencoded和multipart/form-data的区别
Jun 22 PHP
详谈PHP文件目录基础操作
Nov 11 PHP
[原创]php获取数组中键值最大数组项的索引值
Mar 17 PHP
分享php多功能图片处理类
May 15 PHP
Nginx环境下PHP flush失效的解决方法
Oct 19 PHP
PHP单例模式数据库连接类与页面静态化实现方法
Mar 20 PHP
laravel 输出最后执行sql 附:whereIn的使用方法
Oct 10 PHP
详解phpstorm2020最新破解方法
Sep 17 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
用mysql_fetch_array()获取当前行数据的方法详解
2013/06/05 PHP
PHP编写学校网站上新生注册登陆程序的实例分享
2016/03/21 PHP
PHP实现的DES加密解密封装类完整实例
2017/04/29 PHP
Laravel 5.4向IoC容器中添加自定义类的方法示例
2017/08/15 PHP
js Flash插入函数免激活代码
2009/03/31 Javascript
jquery validation插件表单验证的一个例子
2010/03/03 Javascript
jQuery操作元素css样式的三种方法
2014/06/04 Javascript
提交按钮的name='submit'引起的js失效问题及原因
2015/02/25 Javascript
javascript如何写热点图
2015/12/08 Javascript
JS对HTML表格进行增删改操作
2016/08/22 Javascript
JSON 对象未定义错误的解决方法
2016/09/29 Javascript
基于JQuery实现的跑马灯效果(文字无缝向上翻动)
2016/12/02 Javascript
Angular JS数据的双向绑定详解及实例
2016/12/31 Javascript
vuejs指令详解
2017/02/07 Javascript
详解AngularJS 路由 resolve用法
2017/04/24 Javascript
利用node.js如何搭建一个简易的即时响应服务器
2017/05/28 Javascript
Javascript三种字符串连接方式及性能比较
2019/05/28 Javascript
vue限制输入框只能输入8位整数和2位小数的代码
2019/11/06 Javascript
浅谈JavaScript中你可能不知道URL构造函数的属性
2020/07/13 Javascript
JavaScript 实现继承的几种方式
2021/02/19 Javascript
[48:32]VGJ.T vs Fnatic 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
python的dict,set,list,tuple应用详解
2014/07/24 Python
在Python的Django框架中生成CSV文件的方法
2015/07/22 Python
python动态加载包的方法小结
2016/04/18 Python
Python利用WMI实现ping命令的例子
2019/08/14 Python
Python根据字符串调用函数过程解析
2020/11/05 Python
WatchShop法国:英国排名第一的独立手表零售商
2020/02/17 全球购物
远东集团网络工程师面试题
2014/10/20 面试题
英语感恩演讲稿
2014/01/14 职场文书
高中生家长寄语大全
2014/04/03 职场文书
五心教育心得体会
2014/09/04 职场文书
自愿离婚协议书范本
2014/09/13 职场文书
地陪导游欢迎词
2015/01/26 职场文书
撤诉状格式范本
2015/05/19 职场文书
工人先锋号事迹材料(2016精选版)
2016/03/01 职场文书
Python实现对齐打印 format函数的用法
2022/04/28 Python