记得在之前的一篇名为《UCENTER 会员同步登录通讯原理》的文章中,我说到了,在所有的应用中要想向Ucenter的服务器端发送数据,都调用到了一个函数(uc_api_post)。其实这个函数里面的学问蛮大的。他涉及的东西很多,我们一一来分析:
ucenter客户端向服务器端发送请求的原理解析:
当我们一个应用(UCHome)向Ucenter发送一个同步登陆或者同步退出时,该应用(UCHome)是怎么想用
服务器端发送数据请求的呢?
以同步登陆为例,当我们调用函数uc_user_synlogin(),此函数调用函数uc_api_post(),并且传递相关的mod的值和action的值,我们通过找到该函数知道,此函数调用的有两个函数:uc_api_requestdata()和uc_fopen2(),函数uc_api_requestdata是组织一些带参数的URL形式,函数uc_fopen2()最终调用uc_fopen()通过fsockopen()套接字实现打开远程文件的功能。
这个过程中最主要的功能就是这个套接字的使用了。我们来看下这个函数:
functionuc_fopen($url,$limit = 0, $post= '', $cookie = '',$bysocket = FALSE, $ip = '',$timeout = 15, $block= TRUE) {
$return= '';
$matches= parse_url($url);//解析URL
!isset($matches['host']) && $matches['host'] ='';//获得主机名称
!isset($matches['path']) && $matches['path'] ='';//当前文件名
!isset($matches['query']) && $matches['query'] =''; //参数
!isset($matches['port']) && $matches['port'] ='';//端口
$host= $matches['host'];
$path= $matches['path'] ?$matches['path'].($matches['query'] ? '?'.$matches['query'] :'') : '/';
$port= !empty($matches['port']) ?$matches['port'] : 80;
//预处理要写入远程文件的HEAD头信息和参数$post;
if($post) {
$out= "POST $path HTTP/1.0\r\n";
$out.= "Accept: */*\r\n";
//$out .= "Referer: $boardurl\r\n";
$out.= "Accept-Language: zh-cn\r\n";
$out.= "Content-Type: application/x-www-form-urlencoded\r\n";
$out.= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n";
$out.= "Host: $host\r\n";
$out.= 'Content-Length: '.strlen($post)."\r\n";
$out.= "Connection: Close\r\n";
$out.= "Cache-Control: no-cache\r\n";
$out.= "Cookie: $cookie\r\n\r\n";
$out.= $post;
}else {
$out= "GET $path HTTP/1.0\r\n";
$out.= "Accept: */*\r\n";
//$out .= "Referer: $boardurl\r\n";
$out.= "Accept-Language: zh-cn\r\n";
$out.= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n";
$out.= "Host: $host\r\n";
$out.= "Connection: Close\r\n";
$out.= "Cookie: $cookie\r\n\r\n";
}
//使用fsockopen打开远程连接
$fp= @fsockopen(($ip? $ip : $host), $port,$errno, $errstr,$timeout);
if(!$fp) {
return'';//note $errstr : $errno \r\n
}else {
stream_set_blocking($fp,$block);//让程序无阻塞
stream_set_timeout($fp,$timeout); //超时设置
@fwrite($fp,$out);
$status= stream_get_meta_data($fp); //读取数据流
if(!$status['timed_out']) {//判断是否超时(超时时该值为空,否则为1)
while(!feof($fp)) {
if(($header= @fgets($fp)) && ($header== "\r\n" || $header == "\n")) {
break;
}
}
$stop= false;
while(!feof($fp) && !$stop) {
//获取服务器端传输来的数据(这里为一些JS串)
$data= fread($fp, ($limit== 0 || $limit > 8192 ? 8192 : $limit));
$return.= $data;
if($limit) {
$limit-= strlen($data);
$stop= $limit <= 0;
}
}
}
@fclose($fp);
return$return;
}
}
当客户端向服务器端请求时,会调用套接字发送head请求头信息,并且带上客户端发送给服务器端的数据,服务器接受这些数据之后经过一系列的处理之后返回一些JS字符串。这些字符串数据被打开的套接字fsockopen()接收并且存储在$return变量中,之后便是一步步的返回给最初调用的函数如:uc_user_synlogin(),这就是为什么我们把这个函数的返回值输出来是一串JS字符串了。
这样子 整个Ucenter的跨域访问就彻底结束了。。。