读实现
wrapper里边有position和seek等概念,但是很多服务其实是一次性就读取全部数据的,这个可以在stream_open的时候一次性读回,放到一个属性中,以后seek和tell的时候直接操作属性里边存放的数据就可以了.
url_stat的实现
在wrapper class的实现中,url_stat的实现是个难点.必须正确的实现url_stat才能使is_writable和is_readable等查询文件元信息的函数正常工作.
而我们需要为我们的虚设备伪造这些值.以mc为例,我给大家一些参考数据.
url_stat应该返回一个数组,分13个项,内容如下:
dev 设备号- 写0即可
ino inode号 - 写0即可
mode 文件mode - 这个是文件的权限控制符号,稍后详细说明
nlink link - 写0即可.
uid uid - Linux上用posix_get_uid可以取到,windows上为0
gid gid - Linux上用posix_get_gid可以取到,windows上为0
rdev 设备类型 - 当为inode设备时有值
size 文件大小
atime 最后读时间 格式为unix时间戳
mtime 最后写时间
ctime 创建时间
blksize blocksize of filesystem IO 写零即可
blocks number of 512-byte blocks allocated 写零即可
其中mode的值必须写对
如果是文件,其值为
0100000 + 文件权限 ; 如 0100000 + 0777;
如果是目录,其值为
040000 + 目录权限 ; 如 0400000 + 0777;
可以重载标准协议
根据实际测试来看,用stream_wrapper_unregister可以卸载掉http等内置协议.这就方便我们完全无缝的替换用户的一些操作,比如file_get_contents(‘http://sae.sina.com.cn')到我们自己实现的服务上.
知识点补充:
php wrapper实现
【背景】
做一个thrift client的wrapper,用以实现对于服务器的重试逻辑。
【关键点】
1. wrapper要求跟用client一样方便。
2. 当某个服务器挂掉之后可以随机选另一台重试。
3. 用到的php几个关键特性: __call()(magic function,当访问的对象函数不存在时会调用这个), ReflectionClass 反射类及其其成员函数newInstanceArgs , call_user_func_array回调函数。
直接看代码吧(某位牛人写的,not me):
#!/usr/bin/env php
<?php
namespace wrapper;
error_reporting(E_ALL);
require_once '/usr/local/Cellar/thrift/0.9.1/Thrift/ClassLoader/ThriftClassLoader.php';
use Thrift\ClassLoader\ThriftClassLoader;
$GEN_DIR = realpath(dirname(__FILE__).'/..').'/gen-php';
$loader = new ThriftClassLoader();
$loader->registerNamespace('Thrift', '/usr/local/Cellar/thrift/0.9.1/');
$loader->registerDefinition('xiaoju', $GEN_DIR);
$loader->register();
use Thrift\Protocol\TBinaryProtocol;
use Thrift\Transport\TSocket;
use Thrift\Transport\THttpClient;
use Thrift\Transport\TBufferedTransport;
use Thrift\Exception\TException;
class RetryWrapper {
public function __construct($classname, $hosts) {
$this->clazz = new \ReflectionClass($classname);
$this->hosts = $hosts;
}
public function __call($method, $args) {
shuffle($this->hosts);
foreach ($this->hosts as $key => $host) {
try {
return $this->inner_call($host, $method, $args);
} catch (TException $ex) {
$msg = $ex->getMessage();
if (!strstr($msg, 'TSocket')) {
throw $ex;
}
}
}
throw new TException("all server down!");
}
public function inner_call($host, $method, $args) {
$tmp = explode(":", $host);
$socket = new TSocket($tmp[0], (int)$tmp[1]);
$transport = new TBufferedTransport($socket, 1024, 1024);
$protocol = new TBinaryProtocol($transport);
$client = $this->clazz->newInstanceArgs(array($protocol));
$transport->open();
$result = call_user_func_array(array($client, $method), $args);
$transport->close();
return $result;
}
}
$hosts = array('localhost:9090', 'localhost:9091');
$wrapper = new RetryWrapper("\xxx\xx\MessageServiceClient", $hosts, 3);
$data = array('businessId' => 300100001, 'phones' => array('2','2','3'), 'message' => 'asdfqer') ;
$message = new \xxx\xx\Message($data);
print $wrapper->sendMessage($message);
print "\n";
?>
内容版权声明:除非注明,否则皆为本站原创文章。
