看了HTTPSQS,自己尝试开发了队列服务器。原理是借鉴HTTPSQS,只是通信协议层没有使用HTTP协议,而是自己的定的协议规则。
一是为了练手,练习检测内存泄露同时巩固指针的使用。
二是为了理解通信协议。
目前只支持Windows下的编译,后面会支持Linux。
我每次都是先在windows下开发,之后再到调试支持linux下的编译。因为Linux的桌面版真心蛋疼,还不如直接windows下开发,然后通过虚拟机下的调试来支持Linux快。
现有支持的功能:
1.创建队列
2.获取队列
3.插入队列
4.删除队列
5.清空队列
6.队列状态
后续还会支持事务,事务与队列的关系可以参考Redis的设计实现:http://www.redisbook.com/en/latest/feature/transaction.html
一、开发用到的库
1、libevent:通信框架
2、glib:跨平台的基础库
3、Tokyo Cabinet:高效的数据存储
二、服务器端通信协议及队列原理
通信协议图:
单个队列图:
多个队列间的关系图直接借用HTTPSQS的:
三、PHP客户端的请求
- <?php
- define('QUEUE_MAX_LENGTH', 10000);
- class QueueSocket{
- private $socket;
- private $errmsg;
- public function __construct($host, $port){
- $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
- socket_bind($this->socket, $host);
- if(!socket_connect($this->socket, $host, $port)){
- $this->set_errmsg("Unable to connect<pre>".socket_strerror(socket_last_error())."</pre>");
- return false;
- }
- return true;
- }
- public function send($cmd, $content){
- if(!is_array($content) || !$content) {
- return false;
- }
- $params = false;
- foreach($content as $key=>$value){
- $params[] = strtoupper($key)."={$value}";
- }
- $params = join('&', $params)."\r\n";
- $binary = pack("a20i1a*", strtoupper($cmd), strlen($params), $params);
- socket_write($this->socket, $binary, strlen($binary));
- }
- public function read(){
- $response = socket_read($this->socket, 256, PHP_BINARY_READ);
- if($response) {
- $response = json_decode($response, true);
- }else{
- return false;
- }
- if(isset($response['errno']) && $response['errno'] > 0)
- $this->set_errmsg($response['errmsg']);
- return $response;
- }
- public function set_errmsg($msg){
- $this->errmsg = $msg;
- }
- public function get_errmsg(){
- return $this->errmsg;
- }
- public function __destory(){
- socket_close($this->socket);
- }
- }
- class QueueClient extends QueueSocket{
- private $appkey;
- public function __construct($host, $port, $appkey){
- $this->appkey = $appkey;
- parent::__construct($host, $port);
- }
- public function create_new_queue($queue_name, $max_length = QUEUE_MAX_LENGTH){
- $this->send("CREATE", array('queue_name'=>$queue_name, 'max_length'=>$max_length, 'appkey'=>$this->appkey));
- return $this->read();
- }
- public function delete_queue($queue_name){
- $this->send("DELETE", array('queue_name'=>$queue_name, 'appkey'=>$this->appkey));
- return $this->read();
- }
- public function clear_queue($queue_name){
- $this->send("CLEAR", array('queue_name'=>$queue_name, 'appkey'=>$this->appkey));
- return $this->read();
- }
- public function put_queue($queue_name, $data){
- if(is_array($data) || is_object($data)) $data = serialize($data);
- $this->send("PUT", array('queue_name'=>$queue_name, 'data'=>$data, 'appkey'=>$this->appkey));
- return $this->read();
- }
- public function get_queue($queue_name){
- $this->send("GET", array('queue_name'=>$queue_name, 'appkey'=>$this->appkey));
- return $this->read();
- }
- public function state($queue_name){
- $this->send("STATE", array('queue_name'=>$queue_name, 'appkey'=>$this->appkey));
- return $this->read();
- }
- }
- $queue_client = new QueueClient("localhost", 8080, 'testkey');
- //test create queue
- $result = $queue_client->create_new_queue("test_queue", 10000);
- print_r($result);
- //test put
- for($i=0; $i<100; $i++){
- $result = $queue_client->put_queue("test_queue", "jinyong");
- print_r($result);
- }
- // test get_queue
- for($i=0; $i<100; $i++){
- $result = $queue_client->get_queue("test_queue");
- print_r($result);
- }
- // test state_queue
- $result = $queue_client->state("test_queue");
- print_r($result);
- // test clear_queue
- $queue_client->clear_queue("test_queue");
下面是客户端请求结果的部分截图:
队列服务器软件下载:http://yunpan.cn/QWsgA3iYXXZ5A
队列服务器源码、PHP客户端源码下载:http://yunpan.cn/QWsgy2UU5NhSE