我们知道,从父进程到子经常的数据传递相对比较容易一些,但是从子进程传递到父进程就比较的困难。
有很多办法实现进程交互,在php中比较方便的是管道通信。当然,还可以通过socket_pair进行通信。
首先是服务器为了应对每一个请求要做的事情(发送一个url序列,url序列用t分割。而结束标记是n)
functionclientHandle(msgsock,obj)
{
nbuf=;
socket_set_block(msgsock);
do{
if(false===(buf=
socket_read(msgsock,,PHP_NORMAL_READ))){obj-error(socket_read()failed:reason:.socket_strerror(socket_last_error(msgsock)));
break;
}
nbuf.=buf;
if(substr(nbuf,-1)!=\n){
continue;
}
nbuf=trim(nbuf);
if(nbuf==quit){
break;
}
if(nbuf==shutdown){
break;
}
url=explode(\t,nbuf);
nbuf=;
talkback=serialize(read_ntitle(url));
socket_write(msgsock,talkback,strlen(talkback));
debug(writetotheclient\n);
break;
}while(true);
}
面代码比较关键的一个部分是read_ntitle,这个函数实现多线程的读取标题。
代码如下:(为每一个urlfork一个线程,然后打开管道,读取到的标题写入到管道里面去,主线程一直的在读取管道数据,直到所有的数据读取完毕,最后删除管道)
functionread_ntitle(arr)
{
pipe=newPipe(multi-read);
foreach(arrask=item)
{
pids[k]=pcntl_fork();
if(!pids[k])
{
pipe-open_write();
pid=posix_getpid();
content=base64_encode(read_title(item));
pipe-write(k,content\n);
pipe-close_write();
debug(k:writesuccess!\n);
exit;
}
}
debug(readbegin!\n);
data=pipe-read_all();
debug(readend!\n);
pipe-rm_pipe();
returnparse_data(data);
}
parse_data代码如下,非常的简单,就不说了。
parse_data代码如下,非常的简单,就不说了。
functionparse_data(data)
{
data=explode(\n,data);
new=array();
foreach(dataasvalue)
{
value=explode(,,value);
if(count(value)==2){
value[1]=base64_decode(value[1]);
new[intval(value[0])]=value[1];
}
}
ksort(new,SORT_NUMERIC);
returnnew;
}
上面代码中,还有一个函数read_title比较有技巧。为了兼容性,我没有采用curl,而是直接采用socket通信。
在下载到title标签后,就停止读取内容,以节省时间。代码如下:
functionread_title(url)
{
url_info=parse_url(url);
if(!isset(url_info[host])
!isset(url_info[scheme])){
returnfalse;
}
host=url_info[host];
port=isset(url_info[port])?url_info[port]:null;
path=isset(url_info[path])?url_info[path]:/;
if(isset(url_info[query]))path.=?.url_info[query];
if(empty(port)){
port=80;
}
if(url_info[scheme]==