/**
  * 发布一条消息
  * @param BigpipeMessagePackage $msg_pacakge
  * @return BigpipePubResult on success or false on failure
  */
 public function send($msg_package)
 {
     if (!$this->_is_started) {
         BigpipeLog::warning("[connection is not established][pipelet:%d]", $this->_pipelet_id);
         return false;
     }
     // 发送CONNECT
     $cmd = new BStompSendFrame();
     if (!$msg_package->store($cmd->message_body)) {
         // 包错误,不用考虑failover了
         BigpipeLog::warning("[fail to store message body]");
         return false;
     }
     if (true === $this->_last_send_ok) {
         // 当上次发送成功才增加session mesage id
         // 否则message id不变,防止重复发送
         $this->_session_msg_id++;
     }
     $cmd->destination = $this->_get_stripe_name();
     // echo "[stripe name][$cmd->destination]<br>";
     $cmd->no_dedupe = $this->_no_dedupe;
     $cmd->session_id = $this->_session_id;
     $cmd->session_message_id = $this->_session_msg_id;
     $cmd->receipt_id = isset($this->unittest) ? 'fake-receipt-id' : BigpipeUtilities::gen_receipt_id();
     if ($this->_enable_checksum) {
         // 发送message包校验
         $cmd->last_checksum = $this->_last_sign;
         $sign = creat_sign_mds64($cmd->message_body);
         $cmd->cur_checksum = $sign[2];
         // 注意函数返回值
         $this->_last_sign = $cmd->cur_checksum;
     }
     // 进入发送流程,
     // 发送失败则进入failover流程,直到failover失败。
     $send_result = false;
     do {
         if (false === $this->_stomp_adapter->send($cmd)) {
             BigpipeLog::warning("[send message error][session:%s][session_msg_id:%u]", $cmd->session_id, $cmd->session_message_id);
             continue;
         }
         $send_result = $this->_check_ack($cmd->receipt_id, $send_result);
         if (false === $send_result) {
             // ACK失败
             // 不用考虑BMQ_E_COMMAND_DUPLICATEMSG, 去重在broker做,
             // 用户不会收到duplicate返回.
             BigpipeLog::warning("[send message ack error][session:%s][session_msg_id:%u]", $cmd->session_id, $cmd->session_message_id);
             continue;
         } else {
             BigpipeLog::notice("[send message success][pipelet:%u][session:%s][session_msg_id:%u]", $this->_pipelet_id, $cmd->session_id, $cmd->session_message_id);
             break;
             // 发布成功
         }
     } while ($this->_failover());
     if (false !== $send_result) {
         $this->_active();
         // 清理failover状态
     } else {
         $this->_last_send_ok = false;
     }
     return $send_result;
 }
 private function _gen_recv_response()
 {
     $topic_id = 65535;
     $bad_topic_id = 0;
     $pkg = new BigpipeMessagePackage();
     $msg = 'This is a test case';
     $pkg->push($msg);
     $msg_body = null;
     $pkg->store($msg_body);
     $sign = creat_sign_mds64($msg_body);
     $frame = new BStompMessageFrame();
     $frame->priority = 10;
     $frame->persistent = 1;
     $frame->no_dedupe = 1;
     $frame->timeout = BigpipeUtilities::get_time_us();
     $frame->destination = 'cluster-for-unittest';
     $frame->session_id = BigpipeUtilities::get_uid();
     $frame->subscribe_id = BigpipeUtilities::get_uid();
     $frame->receipt_id = BigpipeUtilities::gen_receipt_id();
     $frame->session_message_id = BigpipeUtilities::get_uid();
     $frame->topic_message_id = $topic_id;
     $frame->global_message_id = 76248;
     $frame->cur_checksum = $sign[2];
     $frame->last_checksum = 0;
     $frame->message_body = $msg_body;
     $frame->store();
     $good = $frame->buffer();
     // topic message id ´íÎóµÄcase
     $frame->topic_message_id = $bad_topic_id;
     $frame->store();
     $bad_topic = $frame->buffer();
     // message body ´íÎóµÄcase
     $frame->topic_message_id = $topic_id;
     $frame->message_body = '';
     $frame->store();
     $bad_body = $frame->buffer();
     // checksum´íÎóµÄcase
     $frame->message_body = $msg_body;
     $frame->cur_checksum = 201;
     $frame->store();
     $bad_checksum = $frame->buffer();
     // ´´ÔìÒ»¸öerrorµÄ°ü
     $err_pkg = '1';
     $frame->message_body = $err_pkg;
     $err_sign = creat_sign_mds64($err_pkg);
     $frame->cur_checksum = $err_sign[2];
     $frame->store();
     $bad_pkg = $frame->buffer();
     // ´´ÔìÒ»¸öpop errorµÄ°ü
     $frame->message_body = pack("L2", 1, 5);
     // ÕâÊÇÒ»¸ö³¤¶ÈΪ5£¬µ«ÊÇûÓÐÊý¾ÝµÄ»µ°ü
     $empty_sign = creat_sign_mds64($frame->message_body);
     $frame->cur_checksum = $empty_sign[2];
     $frame->store();
     $empty_pkg = $frame->buffer();
     $res_arr = array('good' => $good, 'bad_topic' => $bad_topic, 'bad_body' => $bad_body, 'bad_checksum' => $bad_checksum, 'bad_pkg' => $bad_pkg, 'empty_pkg' => $empty_pkg);
     return $res_arr;
 }
 /**
  * 从read buffer读取一个message package
  * @return false on failure or BigpageMessage on success
  */
 private function _receive()
 {
     $obj = false;
     do {
         $res_body = $this->_stomp_adapter->receive();
         if (null === $res_body) {
             continue;
             // 直接重订阅
         }
         // 接收成功,读取数据
         $msg = new BStompMessageFrame();
         if (!$msg->load($res_body)) {
             // message包问题
             BigpipeLog::warning('[%s:%u][%s][receive msg error][%s]', __FILE__, __LINE__, __FUNCTION__, $msg->last_error_message());
             continue;
         }
         // 读取msg包
         if (-1 != $this->_pipelet_msg_id && $msg->topic_message_id < $this->_pipelet_msg_id) {
             BigpipeLog::warning('[%s:%u][%s][received different start point error][recv: %u][req: %u]', __FILE__, __LINE__, __FUNCTION__, $msg->topic_message_id, $this->_pipelet_msg_id);
             continue;
         }
         $msg_body = $msg->message_body;
         if (empty($msg_body) || false === $msg_body) {
             continue;
             // 接收message失败,failover
         }
         // message 接收成功,返回ack
         if (BStompClientAckType::AUTO == $this->_client_ack_type) {
             // 发送ack包
             $ack = new BStompAckFrame();
             $ack->receipt_id = $msg->receipt_id;
             $ack->topic_message_id = $msg->topic_message_id;
             $ack->destination = $msg->destination;
             $ack->ack_type = BStompIdAckType::TOPIC_ID;
             if (!$this->_stomp_adapter->send($ack)) {
                 // message接收成功,但是ack发送失败,可以不用理会
                 // 因为下次receive时,会进入failover
                 BigpipeLog::warning('[%s:%u][%s][fail to ack message]', __FILE__, __LINE__, __FUNCTION__);
             }
         }
         // 处理message
         if ($this->_enable_checksum) {
             $sign = creat_sign_mds64($msg_body);
             if ($sign[2] != $msg->cur_checksum) {
                 // checksum校验失败, 进入failover
                 BigpipeLog::warning('[%s:%u][%s][message package checksum error][orig:%u][curr:%u][name:%s][msg_id:%u]', __FILE__, __LINE__, __FUNCTION__, $msg->cur_checksum, $sign[2], $this->_get_stripe_name(), $msg->topic_message_id);
                 continue;
             }
         }
         if (!$this->_package->load($msg_body, $msg->topic_message_id)) {
             // 接收的包有问题, 进入failover
             BigpipeLog::warning('[%s:%u][%s][message package error][name:%s][msg_id:%u]', __FILE__, __LINE__, __FUNCTION__, $this->_get_stripe_name(), $msg->topic_message_id);
             continue;
         }
         $obj = $this->_package->pop();
         // 必须能成功取一条message
         if (false === $obj) {
             // 包中的内容有问,进入failover
             BigpipeLog::warning('[%s:%u][%s][empty message package][name:%s][msg_id:%u]', __FILE__, __LINE__, __FUNCTION__, $this->_get_stripe_name(), $msg->topic_message_id);
             continue;
         }
         $this->_active();
         // 设置活跃状态
         $this->_pipelet_msg_id = $msg->topic_message_id + 1;
         if ($this->_get_end_pos() < $this->_pipelet_msg_id) {
             // 已接收到stripe末尾,更换新stripe
             // 主动更新订阅, 如果更新失败也没关系,下次receive时可以处理
             // 这里进入flush_subscribe不需要sleep
             $this->_fo_sleep_time = 0;
             if ($this->_flush_subscribe()) {
                 $this->_active();
                 //
             }
         }
         break;
         // 成功收到message 跳出循环
     } while ($this->_flush_subscribe());
     return $obj;
 }