在PHP中使用Sockets:從Usenet中獲取文件

  作者:Armel Fauveau
  原文地址:http://www.phpbuilder.net/columns/armel20010427.php3
  譯者:許立強feifengxlq@gmail.com
Http://www.phpobject.net/blog/
  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,"AUTHINFOPASS".$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中使用sockets從新聞組獲取文章
在 php 中使用 sockets 從新聞組中獲取文章來源:永遠的 Unix PHP能打開遠程或本地主機上的Socket端口。本文是一個使用Socket的小例子:連接到一個Usenet新聞組服務器,同服務器對話,從新聞組中下載一些文章。 在php...查看完整版>>php中使用sockets從新聞組獲取文章
 
PHP-SOCKETS編程問題
前面一段談到命令行方式的運行。更多請參照1.fopen的應用fopen也可以被稱作被封裝的SOCKET函數。不僅用于文件讀寫,還可以用于SOCKET。FOPEN相當于其他高級語言的INET控件/類,較于FSOCKOPEN,他對于URL的操作更高級...查看完整版>>PHP-SOCKETS編程問題
 
在*.SQL文件裏獲取並使用變量
  熟悉Oracle SQL語法的人可能都知道在*.sql文件裏可以用&1、&2、... &9 ... 變量名稱去獲取並使用變量。    以scott用戶, 舉例如下:  在C盤的根目錄下寫一個SQL文件 c:\sql1.sql   ...查看完整版>>在*.SQL文件裏獲取並使用變量
 
使用Properties從文件獲取屬性
import Java.util.*;import java.io.*;/** * refer to http://www-900.ibm.com/developerWorks/cn/java/j-tiger02254/index_eng.sHtml </br> * or http://www-900.ibm.com/developerWorks/cn/java/j-tiger022...查看完整版>>使用Properties從文件獲取屬性
 
在*.SQL文件裏獲取並使用變量
  熟悉Oracle SQL語法的人可能都知道在*.sql文件裏可以用&1、&2、... &9 ... 變量名稱去獲取並使用變量。  以scott用戶, 舉例如下:  在C盤的根目錄下寫一個SQL文件  c:\sql1.sql  select empno,ename,job...查看完整版>>在*.SQL文件裏獲取並使用變量
 
在*.sql文件裏獲取並使用變量
  熟悉Oracle SQL語法的人可能都知道在*.sql文件裏可以用&1、&2、... &9 ... 變量名稱去獲取並使用變量。 以scott用戶, 舉例如下: 在C盤的根目錄下寫一個SQL文件 c:\sql1.sql select em...查看完整版>>在*.sql文件裏獲取並使用變量
 
使用Usenet(新聞組)的十大理由
使用Usenet(新聞組)的十大理由1. 全球統一的分類。Usenet(新聞組)上有多達幾萬個不同類別的組,而且有著嚴格統一的管理,更重要的是它是按分級原理組織命名的,有著清楚的脈絡可尋。組是Usenet(新聞組)的單位,...查看完整版>>使用Usenet(新聞組)的十大理由
 
使用Properties從文件獲取屬性
import java.util.*;import java.io.*;/** * refer to </br> * or */public class LoadProperties { public static void main(String[] args) throws Exception { Properties prop = new Properties(); /...查看完整版>>使用Properties從文件獲取屬性
 
使用php的zlib壓縮和解壓縮swf文件
  下面是我寫的壓縮和結壓縮swf文件的例子:  //沒有加入判斷swf文件是否已經壓縮,入需要可以根據文件的第一個字節是'F'或者'C'來判斷  壓縮swf文件:      //文件名   $filename = "test.swf";   //打開...查看完整版>>使用php的zlib壓縮和解壓縮swf文件
 
 
回到王朝網路首頁