查看: 1343|回复: 0

[PHP学习] Redis 通讯协议

发表于 2017-10-7 08:43:05
句号论坛
redis命令发送格式:

*<参数数量> CRLF
$<参数 1 的字节数量> CRLF
<参数 1 的数据> CRLF
...
$<参数 N 的字节数量> CRLF
<参数 N 的数据> CRLF
其中CRLF表示 rn

举个例子:set name wuzhc 格式化输出:

*3
$3
set
$4
name
$5
wuzhc

说明:

*开头,表示有多少个参数,例如*3表示有3个参数(set, name, wuzhc)

$开头,表示参数的字节长度,例如$3表示set有3个字节,$4表示name有4个字节

每行rn结尾

通信协议为:
  1. *3\r\n$3\r\nset\r\n$4\r\nname\r\n$5\r\nwuzhc\r\n
复制代码
Redis 回复

状态回复(status reply)的第一个字节是 "+",例如+OK\r\n

错误回复(error reply)的第一个字节是 "-",例如-No such key\r\n

整数回复(integer reply)的第一个字节是 ":",例如:1\r\n

批量回复(bulk reply)的第一个字节是 "$",例如 $5\r\nwuzhc\r\n

多条批量回复(multi bulk reply)的第一个字节是 "*",例如*2\r\n$5\r\nwuzhc\r\n$3r\nage\r\n

PHP 实现Redis客户端
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: wuzhc2016@163.com
  5. * Date: 2017年09月12日
  6. * Time: 9:08
  7. */
  8. class Client
  9. {
  10. private $_socket = null;
  11. public function __construct($ip, $port)
  12. {
  13. $this->_socket = stream_socket_client(
  14. "tcp://{$ip}:{$port}",
  15. $errno,
  16. $errstr,
  17. 1,
  18. STREAM_CLIENT_CONNECT
  19. );
  20. if (!$this->_socket) {
  21. exit($errstr);
  22. }
  23. }
  24. /**
  25. * 执行redis命令
  26. * @param $command
  27. * @return array|bool|string
  28. */
  29. public function exec($command)
  30. {
  31. // 拼装发送命令格式
  32. $command = $this->_execCommand($command);
  33. // 发送命令到redis
  34. fwrite($this->_socket, $command);
  35. // 解析redis响应内容
  36. return $this->_parseResponse();
  37. }
  38. /**
  39. * 将字符改为redis通讯协议格式
  40. * 例如mget name age 格式化为 *3\r\n$4\r\nmget\r\n$4\r\nname\r\n$3\r\nage\r\n
  41. * @param $command
  42. * @return bool|string
  43. */
  44. private function _execCommand($command)
  45. {
  46. $line = '';
  47. $crlf = "\r\n";
  48. $params = explode(' ', $command);
  49. if (empty($params)) {
  50. return $line;
  51. }
  52. // 参数个数
  53. $line .= '*' . count($params) . $crlf;
  54. // 各个参数拼装
  55. foreach ((array)$params as $param) {
  56. $line .= ' . mb_strlen($param, '8bit') . $crlf;
  57. $line .= $param . $crlf;
  58. }
  59. return $line;
  60. }
  61. /**
  62. * 解析redis回复
  63. * @return array|bool|string
  64. */
  65. private function _parseResponse()
  66. {
  67. $line = fgets($this->_socket);
  68. $type = $line[0];
  69. $msg = mb_substr($line, 1, -2, '8bit');
  70. switch ($type) {
  71. // 状态回复
  72. case '+':
  73. if ($msg == 'OK' || $msg == 'PONG') {
  74. return true;
  75. } else {
  76. return $msg;
  77. }
  78. // 错误回复
  79. case '-':
  80. exit($msg);
  81. // 整数回复
  82. case ':':
  83. return $msg;
  84. // 批量回复
  85. case ': // $后面跟数据字节数(长度)
  86. $line = fread($this->_socket, (int)$msg + 2); // 数据字节数 + (\r\n)两个字节
  87. return mb_substr($line, 0, -2, '8bit'); // 去除最后两个字节
  88. // 多条批量回复
  89. case '*': // *表示后面有多少个参数
  90. $data = [];
  91. for ($i = 0; $i < $msg; $i++) {
  92. $data[] = $this->_parseResponse();
  93. }
  94. return $data;
  95. }
  96. }
  97. }
  98. // demo
  99. $client = new Client('127.0.0.1', 6379);
  100. $client->exec('set name wuzhc');
  101. $res = $client->exec('get name');
  102. var_dump($res);
复制代码


太阳http代理AD
回复

使用道具 举报

关闭

站长推荐上一条 /1 下一条