包 | XS |
---|---|
继承关系 | class XSServer » XSComponent |
子类 | XSIndex, XSSearch |
版本 | 1.0.0 |
源代码 | sdk/php/lib/XSServer.class.php |
名称 | 类型 | 描述 | 定义于 |
---|---|---|---|
connString | string | 连接字符串 | XSServer |
project | string | 获取当前项目名称 | XSServer |
respond | XSCommand | 从服务器读取响应指令 | XSServer |
socket | mixed | 获取连接资源描述符 | XSServer |
xs | XS | 服务端关联的 XS 对象 | XSServer |
名称 | 类型 | 描述 | 定义于 |
---|---|---|---|
_conn | XSServer | ||
_flag | XSServer | ||
_project | XSServer | ||
_sendBuffer | XSServer | ||
_sock | XSServer |
名称 | 描述 | 定义于 |
---|---|---|
__construct() | 构造函数, 打开连接 | XSServer |
__destruct() | 析构函数, 关闭连接 | XSServer |
__get() | 魔术方法 __get | XSComponent |
__isset() | 魔术方法 __isset | XSComponent |
__set() | 魔术方法 __set | XSComponent |
__unset() | 魔术方法 __unset | XSComponent |
close() | 关闭连接 | XSServer |
execCommand() | 执行服务端指令并获取返回值 | XSServer |
getConnString() | Returns 连接字符串 | XSServer |
getProject() | 获取当前项目名称 | XSServer |
getRespond() | 从服务器读取响应指令 | XSServer |
getSocket() | 获取连接资源描述符 | XSServer |
hasRespond() | 判断服务端是否有可读数据 | XSServer |
open() | 打开服务端连接 | XSServer |
reopen() | 重新打开连接 | XSServer |
sendCommand() | 往服务器直接发送指令 (无缓存) | XSServer |
setProject() | 设置当前项目 | XSServer |
setTimeout() | 设置服务端超时秒数 | XSServer |
名称 | 描述 | 定义于 |
---|---|---|
check() | 检测服务端的连接情况 | XSServer |
connect() | 连接服务端 | XSServer |
read() | 读取数据 | XSServer |
write() | 写入数据 | XSServer |
连接字符串
获取当前项目名称
从服务器读取响应指令
获取连接资源描述符
服务端关联的 XS 对象
public void __construct(string $conn=NULL, XS $xs=NULL)
| ||
$conn | string | 服务端连接参数 |
$xs | XS | 需要捆绑的 xs 对象 |
public function __construct($conn = null, $xs = null)
{
$this->xs = $xs;
if ($conn !== null) {
$this->open($conn);
}
}
构造函数, 打开连接
public void __destruct()
|
public function __destruct()
{
$this->xs = null;
$this->close();
}
析构函数, 关闭连接
protected void check()
|
protected function check()
{
if ($this->_sock === null) {
throw new XSException('No server connection');
}
if ($this->_flag & self::BROKEN) {
throw new XSException('Broken server connection');
}
}
检测服务端的连接情况
public void close(bool $ioerr=false)
| ||
$ioerr | bool | 关闭调用是否由于 IO 错误引起的, 以免发送 quit 指令 |
public function close($ioerr = false)
{
if ($this->_sock && !($this->_flag & self::BROKEN)) {
if (!$ioerr && $this->_sendBuffer !== '') {
$this->write($this->_sendBuffer);
$this->_sendBuffer = '';
}
if (!$ioerr && !($this->_flag & self::FILE)) {
$cmd = new XSCommand(XS_CMD_QUIT);
fwrite($this->_sock, $cmd);
}
fclose($this->_sock);
$this->_flag |= self::BROKEN;
}
}
关闭连接 附带发送发送 quit 命令
protected void connect()
|
protected function connect()
{
// connect to server
$conn = $this->_conn;
if (is_int($conn) || is_numeric($conn)) {
$host = 'localhost';
$port = intval($conn);
} elseif (!strncmp($conn, 'file://', 7)) {
// write-only for saving index exchangable data to file
// NOTE: this will cause file content be turncated
$conn = substr($conn, 7);
if (($sock = @fopen($conn, 'wb')) === false) {
throw new XSException('Failed to open local file for writing: `' . $conn . '\'');
}
$this->_flag |= self::FILE;
$this->_sock = $sock;
return;
} elseif (($pos = strpos($conn, ':')) !== false) {
$host = substr($conn, 0, $pos);
$port = intval(substr($conn, $pos + 1));
} else {
$host = 'unix://' . $conn;
$port = -1;
}
if (($sock = @fsockopen($host, $port, $errno, $error, 5)) === false) {
throw new XSException($error . '(C#' . $errno . ', ' . $host . ':' . $port . ')');
}
// set socket options
$timeout = intval(ini_get('max_execution_time'));
$timeout = $timeout > 0 ? ($timeout - 1) : 30;
stream_set_blocking($sock, true);
stream_set_timeout($sock, $timeout);
$this->_sock = $sock;
}
连接服务端
public mixed execCommand(mixed $cmd, int $res_arg=0, int $res_cmd=128)
| ||
$cmd | mixed | 要提交的指令, 若不是 XSCommand 实例则作为构造函数的第一参数创建对象 |
$res_arg | int | 要求的响应参数, 默认为 XS_CMD_NONE 即不检测, 若检测结果不符 则认为命令调用失败, 会返回 false 并设置相应的出错信息 |
$res_cmd | int | 要求的响应指令, 默认为 XS_CMD_OK 即要求结果必须正确. |
{return} | mixed | 若无需要检测结果则返回 true, 其它返回响应的 XSCommand 对象 |
public function execCommand($cmd, $res_arg = XS_CMD_NONE, $res_cmd = XS_CMD_OK)
{
// create command object
if (!$cmd instanceof XSCommand) {
$cmd = new XSCommand($cmd);
}
// just cache the cmd for those need not answer
if ($cmd->cmd & 0x80) {
$this->_sendBuffer .= $cmd;
return true;
}
// send cmd to server
$buf = $this->_sendBuffer . $cmd;
$this->_sendBuffer = '';
$this->write($buf);
// return true directly for local file
if ($this->_flag & self::FILE) {
return true;
}
// got the respond
$res = $this->getRespond();
// check respond
if ($res->cmd === XS_CMD_ERR && $res_cmd != XS_CMD_ERR) {
throw new XSException($res->buf, $res->arg);
}
// got unexpected respond command
if ($res->cmd != $res_cmd || ($res_arg != XS_CMD_NONE && $res->arg != $res_arg)) {
throw new XSException('Unexpected respond {CMD:' . $res->cmd . ', ARG:' . $res->arg . '}');
}
return $res;
}
执行服务端指令并获取返回值
public string getConnString()
| ||
{return} | string | 连接字符串 |
public function getConnString()
{
$str = $this->_conn;
if (is_int($str) || is_numeric($str)) {
$str = 'localhost:' . $str;
} elseif (strpos($str, ':') === false) {
$str = 'unix://' . $str;
}
return $str;
}
public string getProject()
| ||
{return} | string | 项目名称 |
获取当前项目名称
public XSCommand getRespond()
| ||
{return} | XSCommand | 成功返回响应指令 |
public function getRespond()
{
// read data from server
$buf = $this->read(8);
$hdr = unpack('Ccmd/Carg1/Carg2/Cblen1/Iblen', $buf);
$res = new XSCommand($hdr);
$res->buf = $this->read($hdr['blen']);
$res->buf1 = $this->read($hdr['blen1']);
return $res;
}
从服务器读取响应指令
public mixed getSocket()
| ||
{return} | mixed | 连接标识, 仅用于内部测试等目的 |
获取连接资源描述符
public bool hasRespond()
| ||
{return} | bool | 如果有返回 true, 否则返回 false |
public function hasRespond()
{
// check socket
if ($this->_sock === null || $this->_flag & (self::BROKEN | self::FILE)) {
return false;
}
$wfds = $xfds = array();
$rfds = array($this->_sock);
$res = stream_select($rfds, $wfds, $xfds, 0, 0);
return $res > 0;
}
判断服务端是否有可读数据 用于某些特别情况在 getRespond 前先调用和判断, 以免阻塞
public void open(mixed $conn)
| ||
$conn | mixed | 服务端连接参数, 支持: <端口号|host:port|本地套接字路径> |
public function open($conn)
{
$this->close();
$this->_conn = $conn;
$this->_flag = self::BROKEN;
$this->_sendBuffer = '';
$this->_project = null;
$this->connect();
$this->_flag ^= self::BROKEN;
if ($this->xs instanceof XS) {
$this->setProject($this->xs->getName());
}
}
打开服务端连接 如果已关联 XS 对象, 则会同时切换至相应的项目名称
protected string read(int $len)
| ||
$len | int | 要读入的长度 |
{return} | string | 成功时返回读到的字符串 |
protected function read($len)
{
// quick return for zero size
if ($len == 0) {
return '';
}
// loop to send data
$this->check();
for ($buf = '', $size = $len;;) {
$bytes = fread($this->_sock, $len);
if ($bytes === false || strlen($bytes) == 0) {
break;
}
$len -= strlen($bytes);
$buf .= $bytes;
if ($len === 0) {
return $buf;
}
}
// error occured
$meta = stream_get_meta_data($this->_sock);
$this->close(true);
$reason = $meta['timed_out'] ? 'timeout' : ($meta['eof'] ? 'closed' : 'unknown');
$msg = 'Failed to recv the data from server completely ';
$msg .= '(SIZE:' . ($size - $len) . '/' . $size . ', REASON:' . $reason . ')';
throw new XSException($msg);
}
读取数据
public XSServer reopen(bool $force=false)
| ||
$force | bool | 是否强制重新连接, 默认为否 |
{return} | XSServer | 返回自己, 以便串接操作 |
public function reopen($force = false)
{
if ($this->_flag & self::BROKEN || $force === true) {
$this->open($this->_conn);
}
return $this;
}
重新打开连接 仅应用于曾经成功打开的连并且异常关闭了
public void sendCommand(mixed $cmd)
| ||
$cmd | mixed | 要提交的指令, 支持 XSCommand 实例或 cmd 构造函数的第一参数 |
public function sendCommand($cmd)
{
if (!$cmd instanceof XSCommand) {
$cmd = new XSCommand($cmd);
}
$this->write(strval($cmd));
}
往服务器直接发送指令 (无缓存)
public void setProject(string $name, string $home='')
| ||
$name | string | 项目名称 |
$home | string | 项目在服务器上的目录路径, 可选参数(不得超过255字节). |
public function setProject($name, $home = '')
{
if ($name !== $this->_project) {
$cmd = array('cmd' => XS_CMD_USE, 'buf' => $name, 'buf1' => $home);
$this->execCommand($cmd, XS_CMD_OK_PROJECT);
$this->_project = $name;
}
}
设置当前项目
public void setTimeout(int $sec)
| ||
$sec | int | 秒数, 设为 0则永不超时直到客户端主动关闭 |
public function setTimeout($sec)
{
$cmd = array('cmd' => XS_CMD_TIMEOUT, 'arg' => $sec);
$this->execCommand($cmd, XS_CMD_OK_TIMEOUT_SET);
}
设置服务端超时秒数
protected void write(string $buf, string $len=0)
| ||
$buf | string | 要写入的字符串 |
$len | string | 要写入的长度, 默认为字符串长度 |
protected function write($buf, $len = 0)
{
// quick return for empty buf
$buf = strval($buf);
if ($len == 0 && ($len = $size = strlen($buf)) == 0) {
return true;
}
// loop to send data
$this->check();
while (true) {
$bytes = fwrite($this->_sock, $buf, $len);
if ($bytes === false || $bytes === 0 || $bytes === $len) {
break;
}
$len -= $bytes;
$buf = substr($buf, $bytes);
}
// error occured
if ($bytes === false || $bytes === 0) {
$meta = stream_get_meta_data($this->_sock);
$this->close(true);
$reason = $meta['timed_out'] ? 'timeout' : ($meta['eof'] ? 'closed' : 'unknown');
$msg = 'Failed to send the data to server completely ';
$msg .= '(SIZE:' . ($size - $len) . '/' . $size . ', REASON:' . $reason . ')';
throw new XSException($msg);
}
}
写入数据
包 | XS |
---|---|
继承关系 | class XSServer » XSComponent |
子类 | XSIndex, XSSearch |
版本 | 1.0.0 |
源代码 | sdk/php/lib/XSServer.class.php |
名称 | 类型 | 描述 | 定义于 |
---|---|---|---|
connString | string | 连接字符串 | XSServer |
project | string | 获取当前项目名称 | XSServer |
respond | XSCommand | 从服务器读取响应指令 | XSServer |
socket | mixed | 获取连接资源描述符 | XSServer |
xs | XS | 服务端关联的 XS 对象 | XSServer |
名称 | 类型 | 描述 | 定义于 |
---|---|---|---|
_conn | XSServer | ||
_flag | XSServer | ||
_project | XSServer | ||
_sendBuffer | XSServer | ||
_sock | XSServer |
名称 | 描述 | 定义于 |
---|---|---|
__construct() | 构造函数, 打开连接 | XSServer |
__destruct() | 析构函数, 关闭连接 | XSServer |
__get() | 魔术方法 __get | XSComponent |
__isset() | 魔术方法 __isset | XSComponent |
__set() | 魔术方法 __set | XSComponent |
__unset() | 魔术方法 __unset | XSComponent |
close() | 关闭连接 | XSServer |
execCommand() | 执行服务端指令并获取返回值 | XSServer |
getConnString() | Returns 连接字符串 | XSServer |
getProject() | 获取当前项目名称 | XSServer |
getRespond() | 从服务器读取响应指令 | XSServer |
getSocket() | 获取连接资源描述符 | XSServer |
hasRespond() | 判断服务端是否有可读数据 | XSServer |
open() | 打开服务端连接 | XSServer |
reopen() | 重新打开连接 | XSServer |
sendCommand() | 往服务器直接发送指令 (无缓存) | XSServer |
setProject() | 设置当前项目 | XSServer |
setTimeout() | 设置服务端超时秒数 | XSServer |
名称 | 描述 | 定义于 |
---|---|---|
check() | 检测服务端的连接情况 | XSServer |
connect() | 连接服务端 | XSServer |
read() | 读取数据 | XSServer |
write() | 写入数据 | XSServer |
连接字符串
获取当前项目名称
从服务器读取响应指令
获取连接资源描述符
服务端关联的 XS 对象
public void __construct(string $conn=NULL, XS $xs=NULL)
| ||
$conn | string | 服务端连接参数 |
$xs | XS | 需要捆绑的 xs 对象 |
public function __construct($conn = null, $xs = null)
{
$this->xs = $xs;
if ($conn !== null) {
$this->open($conn);
}
}
构造函数, 打开连接
public void __destruct()
|
public function __destruct()
{
$this->xs = null;
$this->close();
}
析构函数, 关闭连接
protected void check()
|
protected function check()
{
if ($this->_sock === null) {
throw new XSException('No server connection');
}
if ($this->_flag & self::BROKEN) {
throw new XSException('Broken server connection');
}
}
检测服务端的连接情况
public void close(bool $ioerr=false)
| ||
$ioerr | bool | 关闭调用是否由于 IO 错误引起的, 以免发送 quit 指令 |
public function close($ioerr = false)
{
if ($this->_sock && !($this->_flag & self::BROKEN)) {
if (!$ioerr && $this->_sendBuffer !== '') {
$this->write($this->_sendBuffer);
$this->_sendBuffer = '';
}
if (!$ioerr && !($this->_flag & self::FILE)) {
$cmd = new XSCommand(XS_CMD_QUIT);
fwrite($this->_sock, $cmd);
}
fclose($this->_sock);
$this->_flag |= self::BROKEN;
}
}
关闭连接 附带发送发送 quit 命令
protected void connect()
|
protected function connect()
{
// connect to server
$conn = $this->_conn;
if (is_int($conn) || is_numeric($conn)) {
$host = 'localhost';
$port = intval($conn);
} elseif (!strncmp($conn, 'file://', 7)) {
// write-only for saving index exchangable data to file
// NOTE: this will cause file content be turncated
$conn = substr($conn, 7);
if (($sock = @fopen($conn, 'wb')) === false) {
throw new XSException('Failed to open local file for writing: `' . $conn . '\'');
}
$this->_flag |= self::FILE;
$this->_sock = $sock;
return;
} elseif (($pos = strpos($conn, ':')) !== false) {
$host = substr($conn, 0, $pos);
$port = intval(substr($conn, $pos + 1));
} else {
$host = 'unix://' . $conn;
$port = -1;
}
if (($sock = @fsockopen($host, $port, $errno, $error, 5)) === false) {
throw new XSException($error . '(C#' . $errno . ', ' . $host . ':' . $port . ')');
}
// set socket options
$timeout = intval(ini_get('max_execution_time'));
$timeout = $timeout > 0 ? ($timeout - 1) : 30;
stream_set_blocking($sock, true);
stream_set_timeout($sock, $timeout);
$this->_sock = $sock;
}
连接服务端
public mixed execCommand(mixed $cmd, int $res_arg=0, int $res_cmd=128)
| ||
$cmd | mixed | 要提交的指令, 若不是 XSCommand 实例则作为构造函数的第一参数创建对象 |
$res_arg | int | 要求的响应参数, 默认为 XS_CMD_NONE 即不检测, 若检测结果不符 则认为命令调用失败, 会返回 false 并设置相应的出错信息 |
$res_cmd | int | 要求的响应指令, 默认为 XS_CMD_OK 即要求结果必须正确. |
{return} | mixed | 若无需要检测结果则返回 true, 其它返回响应的 XSCommand 对象 |
public function execCommand($cmd, $res_arg = XS_CMD_NONE, $res_cmd = XS_CMD_OK)
{
// create command object
if (!$cmd instanceof XSCommand) {
$cmd = new XSCommand($cmd);
}
// just cache the cmd for those need not answer
if ($cmd->cmd & 0x80) {
$this->_sendBuffer .= $cmd;
return true;
}
// send cmd to server
$buf = $this->_sendBuffer . $cmd;
$this->_sendBuffer = '';
$this->write($buf);
// return true directly for local file
if ($this->_flag & self::FILE) {
return true;
}
// got the respond
$res = $this->getRespond();
// check respond
if ($res->cmd === XS_CMD_ERR && $res_cmd != XS_CMD_ERR) {
throw new XSException($res->buf, $res->arg);
}
// got unexpected respond command
if ($res->cmd != $res_cmd || ($res_arg != XS_CMD_NONE && $res->arg != $res_arg)) {
throw new XSException('Unexpected respond {CMD:' . $res->cmd . ', ARG:' . $res->arg . '}');
}
return $res;
}
执行服务端指令并获取返回值
public string getConnString()
| ||
{return} | string | 连接字符串 |
public function getConnString()
{
$str = $this->_conn;
if (is_int($str) || is_numeric($str)) {
$str = 'localhost:' . $str;
} elseif (strpos($str, ':') === false) {
$str = 'unix://' . $str;
}
return $str;
}
public string getProject()
| ||
{return} | string | 项目名称 |
获取当前项目名称
public XSCommand getRespond()
| ||
{return} | XSCommand | 成功返回响应指令 |
public function getRespond()
{
// read data from server
$buf = $this->read(8);
$hdr = unpack('Ccmd/Carg1/Carg2/Cblen1/Iblen', $buf);
$res = new XSCommand($hdr);
$res->buf = $this->read($hdr['blen']);
$res->buf1 = $this->read($hdr['blen1']);
return $res;
}
从服务器读取响应指令
public mixed getSocket()
| ||
{return} | mixed | 连接标识, 仅用于内部测试等目的 |
获取连接资源描述符
public bool hasRespond()
| ||
{return} | bool | 如果有返回 true, 否则返回 false |
public function hasRespond()
{
// check socket
if ($this->_sock === null || $this->_flag & (self::BROKEN | self::FILE)) {
return false;
}
$wfds = $xfds = array();
$rfds = array($this->_sock);
$res = stream_select($rfds, $wfds, $xfds, 0, 0);
return $res > 0;
}
判断服务端是否有可读数据 用于某些特别情况在 getRespond 前先调用和判断, 以免阻塞
public void open(mixed $conn)
| ||
$conn | mixed | 服务端连接参数, 支持: <端口号|host:port|本地套接字路径> |
public function open($conn)
{
$this->close();
$this->_conn = $conn;
$this->_flag = self::BROKEN;
$this->_sendBuffer = '';
$this->_project = null;
$this->connect();
$this->_flag ^= self::BROKEN;
if ($this->xs instanceof XS) {
$this->setProject($this->xs->getName());
}
}
打开服务端连接 如果已关联 XS 对象, 则会同时切换至相应的项目名称
protected string read(int $len)
| ||
$len | int | 要读入的长度 |
{return} | string | 成功时返回读到的字符串 |
protected function read($len)
{
// quick return for zero size
if ($len == 0) {
return '';
}
// loop to send data
$this->check();
for ($buf = '', $size = $len;;) {
$bytes = fread($this->_sock, $len);
if ($bytes === false || strlen($bytes) == 0) {
break;
}
$len -= strlen($bytes);
$buf .= $bytes;
if ($len === 0) {
return $buf;
}
}
// error occured
$meta = stream_get_meta_data($this->_sock);
$this->close(true);
$reason = $meta['timed_out'] ? 'timeout' : ($meta['eof'] ? 'closed' : 'unknown');
$msg = 'Failed to recv the data from server completely ';
$msg .= '(SIZE:' . ($size - $len) . '/' . $size . ', REASON:' . $reason . ')';
throw new XSException($msg);
}
读取数据
public XSServer reopen(bool $force=false)
| ||
$force | bool | 是否强制重新连接, 默认为否 |
{return} | XSServer | 返回自己, 以便串接操作 |
public function reopen($force = false)
{
if ($this->_flag & self::BROKEN || $force === true) {
$this->open($this->_conn);
}
return $this;
}
重新打开连接 仅应用于曾经成功打开的连并且异常关闭了
public void sendCommand(mixed $cmd)
| ||
$cmd | mixed | 要提交的指令, 支持 XSCommand 实例或 cmd 构造函数的第一参数 |
public function sendCommand($cmd)
{
if (!$cmd instanceof XSCommand) {
$cmd = new XSCommand($cmd);
}
$this->write(strval($cmd));
}
往服务器直接发送指令 (无缓存)
public void setProject(string $name, string $home='')
| ||
$name | string | 项目名称 |
$home | string | 项目在服务器上的目录路径, 可选参数(不得超过255字节). |
public function setProject($name, $home = '')
{
if ($name !== $this->_project) {
$cmd = array('cmd' => XS_CMD_USE, 'buf' => $name, 'buf1' => $home);
$this->execCommand($cmd, XS_CMD_OK_PROJECT);
$this->_project = $name;
}
}
设置当前项目
public void setTimeout(int $sec)
| ||
$sec | int | 秒数, 设为 0则永不超时直到客户端主动关闭 |
public function setTimeout($sec)
{
$cmd = array('cmd' => XS_CMD_TIMEOUT, 'arg' => $sec);
$this->execCommand($cmd, XS_CMD_OK_TIMEOUT_SET);
}
设置服务端超时秒数
protected void write(string $buf, string $len=0)
| ||
$buf | string | 要写入的字符串 |
$len | string | 要写入的长度, 默认为字符串长度 |
protected function write($buf, $len = 0)
{
// quick return for empty buf
$buf = strval($buf);
if ($len == 0 && ($len = $size = strlen($buf)) == 0) {
return true;
}
// loop to send data
$this->check();
while (true) {
$bytes = fwrite($this->_sock, $buf, $len);
if ($bytes === false || $bytes === 0 || $bytes === $len) {
break;
}
$len -= $bytes;
$buf = substr($buf, $bytes);
}
// error occured
if ($bytes === false || $bytes === 0) {
$meta = stream_get_meta_data($this->_sock);
$this->close(true);
$reason = $meta['timed_out'] ? 'timeout' : ($meta['eof'] ? 'closed' : 'unknown');
$msg = 'Failed to send the data to server completely ';
$msg .= '(SIZE:' . ($size - $len) . '/' . $size . ', REASON:' . $reason . ')';
throw new XSException($msg);
}
}
写入数据
一条评论!
connect 报错 链接不上服务端 HTTP ERROR 500
请到论坛 登录 后刷新本页面!