浅谈PHP的Socket模块
九月 28, 2007 | 网站架构 | RSS 2.0
一直以来很少看到有多少人使用php的socket模块来做一些事情,大概大家都把它定位在脚本语言的范畴内吧,但是其实php的socket模块可以做很多事情,包括做ftplist,http post提交,smtp提交,组包并进行特殊报文的交互(如smpp协议),whois查询。这些都是比较常见的查询。
特别是php的socket扩展库可以做的事情简直不会比c差多少。
预备知识:
php的socket连接函数
1、集成于内核的socket
这个系列的函数仅仅只能做主动连接无法实现端口监听相关的功能。而且在4.3.0之前所有socket连接只能工作在阻塞模式下。
此系列函数包括
fsockopen,pfsockopen
这两个函数的具体信息可以查询php.net的用户手册
他们均会返回一个资源编号对于这个资源可以使用几乎所有对文件操作的函数对其进行操作如fgets(),fwrite(), fclose()等单注意的是所有函数遵循这些函数面对网络信息流时的规律,例如:
fread() 从文件指针 handle 读取最多 length 个字节。 该函数在读取完 length 个字节数,或到达 EOF 的时候,或(对于网络流)当一个包可用时就会停止读取文件,视乎先碰到哪种情况。
可以看出对于网络流就必须注意取到的是一个完整的包就停止。
2、php扩展模块带有的socket功能。
php4.x 有这么一个模块extension=php_sockets.dll,RHT9上安装后也有一个extension=php_sockets.so的(这个依稀记得是有的需要确认一下,好久没有玩linux了)
当打开这个此模块以后就意味着php拥有了强大的socket功能,包括listen端口,阻塞及非阻塞模式的切换,multi-client 交互式处理等
这个系列的函数列表参看http://www.php.net/manual/en/ref.sockets.php
看过这个列表觉得是不是非常丰富呢?不过非常遗憾这个模块还非常年轻还有很多地方不成熟,相关的参考文档也非常少:(
我也正在研究中,因此暂时不具体讨论它,仅给大家一个参考文章
http://www.zend.com/pecl/tutorials/sockets.php
下面举例说明:
例子1
简单应用——whois查询
看一段代码
CODE:
<?php
$server=”whois.verisign-grs.com”;//TLD .com whois server
$data = “”;
$domain = “abc.com”;//serch domain
$fp = fsockopen($server,43);
if ($fp) {
fputs($fp,$domain.”");
while (!feof($fp)) {
$data .= fgets($fp,1000);
}
}
fclose($fp);
echo ln2br($data);
}
[Copy to clipboard]
这个应用因该非常常见了:),不用多废话了。
下面看看对于ftplist的应用
CODE:
<?php
$server=”192.168.1.3″;//服务器ip端口用默认的21举例而已所以不要那么复杂
$data = “”;
$fp = fsockopen($server,21);//打开服务器
$data .= fread($fp,1024);//读取状态注意用的fread那么是一个可用报文结束为一段读取。
fwrite($fp,”USER hack”);//登陆信息
$data .= fgets($fp,1024);//读取是否有此用户,是否等待密码
fwrite($fp,”PASS 123456″);//密码
$data .= fgets($fp,1024);//是否验证成功
fwrite($fp,”REST 100″);//重置数据流
$data .= fgets($fp,1024);
fwrite($fp,”PWD”);//当前目录
$data .= fgets($fp,1024);
fwrite($fp,”TYPE A”);//切换传输模式为A——ASCII模式
$data .= fgets($fp,1024);
fwrite($fp,”CWD ./123456″);//更换目录为123456
$data .= fgets($fp,1024);
fwrite($fp,”PASV”);//切换为被动模式
$tstring = fgets($fp,1024);
$data .=$tstring;
$ports=ftp_pasvs($tstring);//获取服务器分配的端口及ip
fwrite($fp,”LIST -al”);//列表
$sock_data=ftp_data_connection($ports);//连接被动模式下的端口
while (!feof($sock_data)) {//循环获取数据
$data .= fgets($sock_data, 1024);
}
echo nl2br($data);
function ftp_pasvs($string)//用于获取被动模式下的相关连接信息
{
$ip_port = preg_replace(”/^(.+
()([0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+)()?.*)$/i”,”2″,$string);
return $ip_port;
}
function ftp_data_connection($ip_port)//连接服务器数据端口
{
$ip_port=trim($ip_port);
if (!preg_match(”/^[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+$/i”, $ip_port)) {
return “false”;
}
$DATA = explode(”,”, $ip_port);
$ipaddr = $DATA[0].”.”.$DATA[1].”.”.$DATA[2].”.”.$DATA[3];
$port = $DATA[4]*256 + $DATA[5];
//echo $port.”|”.$ipaddr;//exit;
$data_connection = @fsockopen($ipaddr, $port);
if (!$data_connection) {
return “false”;
}
return $data_connection;
}
?>
[Copy to clipboard]
以上这段代码作了一下简单的注释应该比较清晰,现说明几点问题。
1、为什么采用fread:因为此函数是以网络包为截断的,使用这样的截断来获得信息可以很好的保持兼容性,因为对于ftpclient来讲服务器是一个未知的环境(wu-ftp,ser-u,g6ftp…),在这样的环境下有利于读取ftp的特征字符串以便以后使用。
2、为什么不用主动模式连接服务器传输数据:主动模式必须客户端指定端口然后进行传输,而php自带的函数并不具备此特性。除非使用扩展库,这样程序兼容性就会。。同时由服务器指定端口避免了客户端寻找合适端口造成的额外负担,尽管这样的负担微乎其微。
与这个代码类似的应用还有estmp发送邮件,管与此应用我不多说,有兴趣的朋友可以到我的blog上看看有相关代码(www.freeplug.org)冰血老弟不介意我做点小广告吧哈哈。
POST,GET提交这个话题很老了:)我想不需要我在这里提起了文章很多。
在看下面一个例子前先提及一组函数pack,unpack。
任何一款拥有socket操作能力的语言都有一个专门用于组包的函数,php也不例外当然这组函数的用途不仅仅是组包。
下面简单的介绍一下:
应用一:
输入16进制或者2进制流。
CODE:
$src=”3B06″;
$binvar = pack(’H*’,$src);
echo $binvar;
[Copy to clipboard]
看看这个程序,相当于下面的程序
CODE:
echo chr(0×3B).chr(0×06);
[Copy to clipboard]
在数据量很小的时候后面的做法,更为简便。但是大量数据的时候,前一种做法则更为实际工整些,代码量也很少。
应用二:
网络数据流拆包
CODE:
$elength = str_len($bin);
extract(unpack(”NLEN/Hcontent”, $bin));
[Copy to clipboard]
将$bin拆成
一维数组并解开到变量$LEN和$content内。
下面看例子了
这个是利用php实现中国移动cmpp登陆消息的一个缩写例子
CODE:
<?php
define(”LOGINID”,0×00000001);//登陆消息
class SMS{
var $host;
var $mtport;
var $moport;
var $connectout;
var $sms_sock;
var $loginuser;
var $loginpass;
var $error_stop=0;
function SMS($host,$user,$pass,$mtport,$moport,$timeout=30,$if_conn=0){
$this->host=$host;
$this->mtport=$mtport;
$this->moport=$moport;
$this->loginuser=$user;
$this->loginpass=$pass;
$if_conn && $this->login();
}
function login(){
$fp=@fsockopen($this->host,$this->mtport,$errno,$errstr,$this->connectout);
if(!$fp){
$this->sms_sock=”;
$this->halt(”error in login num=$errno, msg=$errstr”);
return false;
}else{
//$this->sms_sock=$fp;
$data=pack(”Na10a32″,LOGINID,$this->loginuser,md5($this->loginpass));//这个地方就是组包了
$data=pack(”N”,strlen($data)+4).$data;//$data是实际内容前面这个表示整个报文长度
if(fputs($fp,$data) !== false){
//print_r(unpack(”N”,fread($fp,4)));//此处用于调试时检测用
//print_r(unpack(”N”,fread($fp,4)));
//print_r(unpack(”c”,fread($fp,4)));
//print_r(unpack(”N”,fread($fp,4)));
@fread($fp,12);
$results=@fread($fp,4);
if($results){
$rs=@unpack(”Ncounts”,$results);//返回socket结果。
$this->sms_sock=$fp;
}else{
$this->sms_sock=”;
$this->halt(”error in login: loginid=$this->loginuser loginpass=$this->loginpass”);
return false;
}
}else{
$this->sms_sock=”;
$this->halt(”error in submit logininfo: loginid=$this->loginuser
loginpass=$this->loginpass”);
return false;
}
}
return true;
}
function halt($msg){
echo $msg;
flush();
$this->error_stop && exit;
}
}
[Copy to clipboard]
此例应用:主要用于底层的不依赖于http一类协议的通讯使用。在phpclass这个站点上有个smpp模块更为详细的演示了此类应用有兴趣的朋友可以看看。
末了,不多说。由于时间仓促,有些得不对的地方,望各位用pm通知我,我会及时更正,有什么疑问也可以pm我。
文章: PHP And Socket ◇ Socket基础 在这一章里你将了解到迷人而又让人容易糊涂的套接字(Sockets)。Sockets在PHP中是没有充分利用的功能。今天你将看到产生一个能使用客户端连接的服务器,并在客户端使用socket进行连接,服务器端将详细的处理信息发送给客户端。 ◆ Socket 基础
表一:协议 表三:公共协议 现在你知道了产生一个socket的三个元素,那么我们就在php中使用socket_create()函数来产生一个socket。这个socket_create()函数需要三个参数:一个协议、一个socket类型、一个公共协议。socket_create()函数运行成功返回一个包含socket的资源类型,如果没有成功则返回false。 现在你产生一个socket,然后呢?php提供了几个操纵socket的函数。你能够绑定socket到一个IP,监听一个socket的通信,接受一个socket;现在我们来看一个例子,了解函数是如何产生、接受和监听一个socket。 <?php 上面这个例子产生一个你自己的服务器端。例子第一行, 表四:Socket函数 2条评论 »展开收缩smarty,js九月 28, 2007 | 网站架构 | RSS 2.0展开收缩 –> <{section name=rows loop=$data}> 另外有个别人的 <script type=”text/javascript”> function SwitchMenu(obj){ <body> <div id=”masterdiv”> <table onclick=”SwitchMenu(’sub1′)” onmouseover=”this.style.cursor=’hand’;”> <p onclick=”SwitchMenu(’sub2′)” onmouseover=”this.style.cursor=’hand’;”> <table> <tr class=”submenu” id=”sub3″ style=”display=’none’”> </div> <!– 其它说明 — <span class=”submenu” id=”sub4″ style=”display=’block’”> </body> <script type=”text/javascript”> function SwitchMenu(obj){ <body> <div id=”masterdiv”> <table onclick=”SwitchMenu(’sub1′)” onmouseover=”this.style.cursor=’hand’;”> <p onclick=”SwitchMenu(’sub2′)” onmouseover=”this.style.cursor=’hand’;”> <table> <tr class=”submenu” id=”sub3″ style=”display=’none’”> </div> <!– 其它说明 — <span class=”submenu” id=”sub4″ style=”display=’block’”> </body> 没有评论 »常用的js九月 28, 2007 | mysql | RSS 2.0只能是写限定的东西 代码如下:
<input onkeydown=”if(event.keyCode==13)event.keyCode=9″ > 只能是中文 <input onkeyup=”value=value.replace(/[ -~]/g,”)” onkeydown=”if(event.keyCode==13)event.keyCode=9″> 只能是英文和数字.屏蔽了输入法 <input style=”ime-mode:disabled” onkeydown=”if(event.keyCode==13)event.keyCode=9″> 只能输入英文和数字 <input onkeyup=”value=value.replace(/[W]/g,”) “onbeforepaste=”clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^d]/g,”))” onkeydown=”if(event.keyCode==13)event.keyCode=9″> 只能是数字 <input onkeyup=”value=value.replace(/[^d]/g,”) “onbeforepaste=”clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^d]/g,”))”> 只能显示,不能修改的文本框 <input readOnly value=”只能显示,不能修改”> 只能是数字,判断按键 代码如下: <script language=javascript> function onlyNum() { if(!((event.keyCode>=48&&event.keyCode<=57)||(event.keyCode>=96&&event.keyCode<=105)||(event.keyCode==8))) event.returnValue=false; } </script> <input onkeydown=”onlyNum();”> 附:获取键盘的KeyCode <html> <head> <script language=”javascript”> ns4 = (document.layers) ? true : false; ie4 = (document.all) ? true : false; function keyDown(e){ if(ns4){ var nkey=e.which; var iekey=’现在是ns浏览器’; var realkey=String.fromCharCode(e.which); } if(ie4){ var iekey=event.keyCode; var nkey=’现在是ie浏览器’; var realkey=String.fromCharCode(event.keyCode); if(event.keyCode==32){realkey=” 空格”} if(event.keyCode==13){realkey=” 回车”} if(event.keyCode==27){realkey=” Esc”} if(event.keyCode==16){realkey=” Shift”} if(event.keyCode==17){realkey=” Ctrl”} if(event.keyCode==18){realkey=” Alt”} } alert(’ns浏览器中键值:’+nkey+”+’ie浏览器中键值:’+iekey+”+’实际键为’+realkey); } document.onkeydown = keyDown; if(ns4){ document.captureEvents(Event.KEYDOWN);} </script> </head> <body> //Javascript Document. <hr> <center> <h3>请按任意一个键。。。。</h3> </center> </body> </html> 限制网页用键盘 <body onkeydown=”alert(’禁用’);return false;”> 限制键盘的某个键: <body onkeydown=”if(event.keyCode==num){alert(’禁用’);return false;}> 再加个找按键的值 <script> function show(){ alert(”ASCII代码是:”+event.keyCode); } </script> <body onkeydown=”show()”> 只能是IP地址 <html> <head> <meta http-equiv=”Content-Type” content=”text/html; charset=gb2312″> <meta name=”GENERATOR” content=”Microsoft FrontPage 4.0″> <meta name=”ProgId” content=”FrontPage.Editor.Document”> <style> .a3{width:30;border:0;text-align:center} </style> <script> function mask(obj){ obj.value=obj.value.replace(/[^d]/g,”) key1=event.keyCode if (key1==37 || key1==39) { obj.blur(); nextip=parseInt(obj.name.substr(2,1)) nextip=key1==37?nextip-1:nextip+1; nextip=nextip>=5?1:nextip nextip=nextip<=0?4:nextip eval(”ip”+nextip+”.focus()”) } if(obj.value.length>=3) if(parseInt(obj.value)>=256 || parseInt(obj.value)<=0) { alert(parseInt(obj.value)+”IP地址错误!”) obj.value=”" obj.focus() return false; } else { obj.blur(); nextip=parseInt(obj.name.substr(2,1))+1 nextip=nextip>=5?1:nextip nextip=nextip<=0?4:nextip eval(”ip”+nextip+”.focus()”) } } function mask_c(obj) { clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^d]/g,”)) } </script> <title>IP地址输入</title> </head> <body>IP地址输入 <div style=”border-width:1;border-color:balck;border-style:solid;width:165;font-size:9pt”> <input type=text name=ip1 maxlength=3 class=a3 onkeyup=”mask(this)” onbeforepaste=mask_c()>. <input type=text name=ip2 maxlength=3 class=a3 onkeyup=”mask(this)” onbeforepaste=mask_c()>. <input type=text name=ip3 maxlength=3 class=a3 onkeyup=”mask(this)” onbeforepaste=mask_c()>. <input type=text name=ip4 maxlength=3 class=a3 onkeyup=”mask(this)” onbeforepaste=mask_c()> </div> </body> </html> 用#default#savehistory防止后退清空text文本框: <HTML> <HEAD> <META NAME=”save” CONTENT=”history”> <STYLE> .saveHistory {behavior:url(#default#savehistory);} </STYLE> </HEAD> <BODY> <INPUT class=saveHistory type=text id=oPersistInput> <input type=button onclick=’javascript:location.href=”http://www.webjx.com/”‘ value=’点击进入,再按后退键试试?’> </BODY> </HTML> TEXTAREA自适应文字行数的多少 <textarea rows=1 name=s1 cols=27 onpropertychange=”this.style.posHeight=this.scrollHeight”> 上传预览图片 <img id=pic src=http://www.webjx.com/images/logo.gif> <input type=file name=file><input type=button onclick=pic.src=file.value value=预览图片> <input type=button onclick=alert(file.value) value=图片地址> <input type=button onclick=”file.outerHTML=file.outerHTML.replace(/value=w/g,”)” value=”清除file里字”> 去掉下拉选项的边框 <div style=”position: absolute; left: 10px; top: 10px; width: 115px; height: 20px; clip:rect(2 114 20 2);”> <select> <option >cnpeople</option> <option >cnrose</option> <option >cnbruce</option> </select> &n … 没有评论 »萧瑟的秋雨,寂寞的孤泪九月 28, 2007 | c/c++ | RSS 2.0窗外的冷雨,沥沥下个不停,午夜的钟声,伴随呜咽的我,止不住的泪水恣意流淌。不敢面对快20个月的回忆的点点滴滴,一起的欢声笑语,一起的喜怒哀乐,风中我们一路走来,雨中我们相伴而行,记得大二的暑假我们一起去祖国的南海边,互相照顾,关怀。记得一起在海边,我们一起躺在海边任海风恣意狂吹,记得你一次次下班后我工作,那些珍贵的日子让痛苦,让我珍藏。如今,真让我和她分开,真的是眼哭红了,心已经碎了。每一滴雨都在敲打着我的心,每一滴泪都在流淌着我的难忘的经历。 雨声渐小,风声又起。痛苦未停,心渐变碎。也许今夜的雨未我而下,老天因为我的失恋,为了和我一起痛苦,往事如浮萍般在我眼前掠过,想起你每天早上给我带的饭,想起我们一起美化我们的小房,想起一起踏遍学校的每一个角落,想起我们。。。。太多太多了,让她飘碎在风中,所有的一切都飘落。散落每一条小道。我们有太多的记忆,我们有太多的难忘,我们有太多的经典。 雨点越来越大,痛苦越来越重!!此时的心虽能明白,此时的。。。。。。。。。。。。。。。。。。。。。
没有评论 »大学生建模不简单九月 23, 2007 | 数据结构算法 | RSS 2.0
2007高教社杯全国大学生数学建模竞赛题目 (请先阅读 “对论文格式的统一要求”)
B题:乘公交,看奥运 我国人民翘首企盼的第29届奥运会明年8月将在北京举行,届时有大量观众到现场观看奥运比赛,其中大部分人将会乘坐公共交通工具(简称公交,包括公汽、地铁等)出行。这些年来,城市的公交系统有了很大发展,北京市的公交线路已达800条以上,使得公众的出行更加通畅、便利,但同时也面临多条线路的选择问题。针对市场需求,某公司准备研制开发一个解决公交线路选择问题的自主查询计算机系统。 为了设计这样一个系统,其核心是线路选择的模型与算法,应该从实际情况出发考虑,满足查询者的各种不同需求。请你们解决如下问题: 1、仅考虑公汽线路,给出任意两公汽站点之间线路选择问题的一般数学模型与算法。并根据附录数据,利用你们的模型与算法,求出以下6对起始站→终到站之间的最佳路线(要有清晰的评价说明)。 (1)、S3359→S1828 (2)、S1557→S0481 (3)、S0971→S0485 (4)、S0008→S0073 (5)、S0148→S0485 (6)、S0087→S3676 2、同时考虑公汽与地铁线路,解决以上问题。 3、假设又知道所有站点之间的步行时间,请你给出任意两站点之间线路选择问题的数学模型。
【附录1】基本参数设定 相邻公汽站平均行驶时间(包括停站时间): 3分钟 相邻地铁站平均行驶时间(包括停站时间): 2.5分钟 公汽换乘公汽平均耗时: 5分钟(其中步行时间2分钟) 地铁换乘地铁平均耗时: 4分钟(其中步行时间2分钟) 地铁换乘公汽平均耗时: 7分钟(其中步行时间4分钟) 公汽换乘地铁平均耗时: 6分钟(其中步行时间4分钟) 公汽票价:分为单一票价与分段计价两种,标记于线路后;其中分段计价的票价为:0~20站:1元;21~40站:2元;40站以上:3元 地铁票价:3元(无论地铁线路间是否换乘) 注:以上参数均为简化问题而作的假设,未必与实际数据完全吻合。 【附录2】公交线路及相关信息 (见数据文件B2007dat< 写了个读取文本的小程序,没用c ? */ $aa=str_replace(array(”S”,”END”),” “,$aa); //去除s和end echo(”"); } 转换二维数组 function tran($aa,&$array) ?> 没有评论 »午夜的记忆九月 22, 2007 | linux | RSS 2.0弄那个rss。弄的头晕,以点小错误弄了半天啊呵呵! 经典的大学,经典的回忆,就在此夜,顺便show以下我的桌面,很乱吧 <? 然后再次记录以个小偷程序 <? extract($_GET);extract($_POST); $clinchurl = “http://www.haosf.com”; //目标站 $url = $clinchurl.$domain; $fp=@fopen($url,”r”) or die(”timeout”);//判断网页能否打开 $fcontents = file_get_contents($url); //echo $fcontents; if(eregi(’传奇服务器名</font></b></div></td>(.*)>下一页</a></div></td>’,$fcontents,$regs)) { //上面的(.*)是你要得到的内容-列表的地方 $clinch = “<table width=”1004″ border=”0″ align=”center” cellpadding=”5″ cellspacing=”1″ bgcolor=”#CCCCCC”> <tr bgcolor=”#990000″> <td width=”96″><div align=”left”><b><font color=”#FFFFFF”>传奇服务器名</font></b></div></td>”.$regs[1].”</a></div></td>”; //把得到的内容的html补齐,自己发挥 }//END IF
$clinch=str_replace(’<td width=”1002″ valign=”middle” align=”center”><p><a href=”http://www.4fid.com”><img src=”img/tmj.gif” width=”926″ height=”80″ border=”0″></a></p> <p><a href=”http://www.agdsf.com” target=”_blank”><img src=”img/bazhe1.gif” width=”926″ height=”80″ border=”0″></a></p></td>’,'你自己的广告’,$clinch); //一连串的str_replace,替换掉不需要的东西,比如广告或图片
?> <? include “lanmu.php”; //栏目列表 ?> <iframe width=0 height=0 frameborder=0 scrolling=no src=http://你的站.com/make.php?file=index.html ></iframe> //利用这个判断更新html页面
<?=$clinch?> <? include “foot.php”; ?> make.php //生成html.缓存 <? extract($_GET);extract($_POST);
$url=”http://xxxxxxx.com/chuanqi.php”; if(!$file){ $file=”index.html”;$url=”http://xxxxxxxxxxxx.com/chuanqi.php”; }
/*自己加判断这个$url的语句,来赋予 $file不同的名字———–》生成不同的html名字 比如:
if($file=”wow.html”){ //$file是在人们访问html页面时由iframe传递过来的
$url=”http://xxxxxx/wow.php” //相应的动态页面 } */
$path=$file;
$cache_filetime = filemtime($path);
if (time() – $cache_filetime <= 72000) { //** the cache is not expire echo “还没有必要更新”; }else{
$fp=@fopen($url,”r”) or die(”timeout”);//判断网页能否打开 $fcontents = file_get_contents($url); $handle=fopen($path,’w'); //写入方式打开路径 fwrite($handle,$fcontents); //把刚才替换的内容写进生成的HTML文件 fclose($handle); echo “done”; } 没有评论 »加密小算法九月 17, 2007 | 数学 | RSS 2.0学了网络安全的古典加密算法了,正好用到,顺便写了以个 <? switch($i%6) switch($i%6) $temp1+=$i; $temp1+=$i; 没有评论 »用到的滚动效果九月 14, 2007 | mysql | RSS 2.0
.sqBorder {width:602px; height:64px; padding:10px; border:1px #000000 solid; background:#555555;} 向左滚动
.sqBorder {width:122px; height:182px; padding:10px; border:1px #000000 solid; background:#555555;} 向上滚动
没有评论 »(转)农历转换和突破防盗链九月 14, 2007 | 数学 | RSS 2.0<?php 没有评论 » |


