我们接着前面的文章继续分析,先从完整的接到请求后的处理过程开始。
//接收到完整的数据包后的处理过程
public function onOneRequest($client_id, $request)
{
if($this->parser->isHearBeatRequest($request))
{
//心跳请求,不需要数据回送
}
else if($this->parser->isNormalRequest($request) || $this->parser->isOneWayRequest($request))
{
//获取配置信息
$appConfig = $this->getAppConfig();
//Number of packet loss in a row
$lossNumber = $appConfig['fsof_setting']['loss_number'];
//判断是否开启过载丢包模式
$restOfLostNum = $this->server->getOverloadMonitor()->getLossNum();
if($restOfLostNum > 0)
{
// 加入对过载丢失数据的统计
$this->server->getAppMonitor()->onRequest($request);
//回复客户端
if($restOfLostNum >= $lossNumber)
{
if($this->swoole_server->exist($client_id))
{
$result = 'provider连续过载, 开启丢消息模式';
$this->packResponse($client_id, $request, $result, false, true);
}
}
else
{
if($this->swoole_server->exist($client_id))
{
$result = 'provider开启丢消息模式, 连续丢包中...';
$this->packResponse($client_id, $request, $result, false, true);
}
}
//递减丢包数量
$this->server->getOverloadMonitor()->lossNumDecr();
//监控请求错误处理数量
$this->server->getAppMonitor()->onError($request);
}
else
{
$this->requestProcessor($client_id,$request);
}
}
else
{
$this->logger->error("invalid request = $request");
}
}
//发送回复包
public function packResponse($client_id, $request, $data, $businessError,$frameError)
{
$response = new DubboResponse();//声明response对象
$response->setSn($request->getSn());//设置response的sn属性,这个属性用于追踪一个完整的请求流程
if($frameError){//如果是框架报错
$response->setStatus(DubboResponse::SERVICE_ERROR);//设置response的状态信息
$response->setErrorMsg($data);//设置response的错误信息
}
if($businessError){//如果是业务报错
$response->setErrorMsg($data);//设置response的错误信息
}
$response->setResult($data);//设置回复包的数据信息
$this->sendResponse($response, $client_id);//向该clientid发送回复包response
return $response;
}
public function sendResponse(DubboResponse $response, $client_id)
{
try
{
$send_data = $this->parser->packResponse($response);//调用解析器编码回复包
$send_len = strlen($send_data);//计算数据长度信息
//默认所有server的response最大5M,每个分包允许重发2次,预计最多10次循环,防止网络出错导致server直接挂死在循环中
$cnt = (($send_len / DubboParser::RESPONSE_TCP_SEGMENT_LEN) + 1) * 2;
$tmp_len = $send_len;
for ($i = 0; $i < $cnt; $i++)
{
if ($tmp_len > DubboParser::RESPONSE_TCP_SEGMENT_LEN)
{
//大于1M 分段发送
$tmp_data = substr($send_data, 0, DubboParser::RESPONSE_TCP_SEGMENT_LEN);
//调用swoole的api来发送数据,该数据是回复给clientid的客户端
if ($this->swoole_server->send($client_id, $tmp_data))
{
$tmp_len -= DubboParser::RESPONSE_TCP_SEGMENT_LEN;
$send_data = substr($send_data, DubboParser::RESPONSE_TCP_SEGMENT_LEN);
}
else
{
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
{
$last_error_no = $this->swoole_server->errno();
}
else
{
$last_error_no = swoole_errno();
}
if (0 == $last_error_no)
{
//表示该连接己关闭
$this->logger->error("当前连接己关闭,发送失败");
break;
}
else
{
$this->logger->error('send response split package fail one time!');
}
}
$this->logger->warn('the length of response: '.$send_len.'; send split package '.$i.'/'.$cnt);
}
else
{
//小于1M一次性发完
if ($this->swoole_server->send($client_id, $send_data))
{
break;
}
else
{
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
{
$last_error_no = $this->swoole_server->errno();
}
else
{
$last_error_no = swoole_errno();
}
if (0 == $last_error_no)
{
//表示该连接己关闭
$this->logger->error("当前连接己关闭,发送失败");
break;
}
else
{
$this->logger->error('send response last package fail one time!');
}
}
}
}
}
catch (\Exception $e)
{
$this->logger->error($e->getMessage(), $e);
}
return $send_len;
}