server端會(huì)自動(dòng)嘗試其支持的協(xié)議舌厨,無(wú)需用戶(hù)指定。cntl->protocol()
可獲得當(dāng)前協(xié)議夭问。server能從一個(gè)listen端口建立不同協(xié)議的連接烛卧,不需要為不同的協(xié)議使用不同的listen端口佩微,一個(gè)連接上也可以傳輸多種協(xié)議的數(shù)據(jù)包, 但一般不會(huì)這么做(也不建議)缝彬。
下面分析一下這部分實(shí)現(xiàn):
在服務(wù)端接到新數(shù)據(jù)之后會(huì)調(diào)用CutInputMessage。
_handlers中保存支持的協(xié)議配置哺眯。
首先使用上次成功的協(xié)議解析 _handlers[preferred].parse谷浅,如果成功return;
如果失敗繼續(xù)for循環(huán)解析族购,成功就找到了對(duì)應(yīng)的協(xié)議壳贪,如果失敗繼續(xù)陵珍。
成功后會(huì)執(zhí)行set_preferred_index設(shè)置上一次使用的協(xié)議寝杖,這種方式不適合多個(gè)協(xié)議頻繁切換的請(qǐng)求。
ParseResult InputMessenger::CutInputMessage(
Socket* m, size_t* index, bool read_eof) {
const int preferred = m->preferred_index();
const int max_index = (int)_max_index.load(butil::memory_order_acquire);
// Try preferred handler first. The preferred_index is set on last
// selection or by client.
if (preferred >= 0 && preferred <= max_index
&& _handlers[preferred].parse != NULL) {
ParseResult result =
_handlers[preferred].parse(&m->_read_buf, m, read_eof, _handlers[preferred].arg);
if (result.is_ok() ||
result.error() == PARSE_ERROR_NOT_ENOUGH_DATA) {
*index = preferred;
return result;
} else if (result.error() != PARSE_ERROR_TRY_OTHERS) {
// Critical error, return directly.
LOG_IF(ERROR, result.error() == PARSE_ERROR_TOO_BIG_DATA)
<< "A message from " << m->remote_side()
<< "(protocol=" << _handlers[preferred].name
<< ") is bigger than " << FLAGS_max_body_size
<< " bytes, the connection will be closed."
" Set max_body_size to allow bigger messages";
return result;
}
if (m->CreatedByConnect() &&
// baidu_std may fall to streaming_rpc
(ProtocolType)preferred != PROTOCOL_BAIDU_STD) {
// The protocol is fixed at client-side, no need to try others.
LOG(ERROR) << "Fail to parse response from " << m->remote_side()
<< " by " << _handlers[preferred].name
<< " at client-side";
return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG);
}
// Clear context before trying next protocol which probably has
// an incompatible context with the current one.
if (m->parsing_context()) {
m->reset_parsing_context(NULL);
}
m->set_preferred_index(-1);
}
for (int i = 0; i <= max_index; ++i) {
if (i == preferred || _handlers[i].parse == NULL) {
// Don't try preferred handler(already tried) or invalid handler
continue;
}
ParseResult result = _handlers[i].parse(&m->_read_buf, m, read_eof, _handlers[i].arg);
if (result.is_ok() ||
result.error() == PARSE_ERROR_NOT_ENOUGH_DATA) {
m->set_preferred_index(i);
*index = i;
return result;
} else if (result.error() != PARSE_ERROR_TRY_OTHERS) {
// Critical error, return directly.
LOG_IF(ERROR, result.error() == PARSE_ERROR_TOO_BIG_DATA)
<< "A message from " << m->remote_side()
<< "(protocol=" << _handlers[i].name
<< ") is bigger than " << FLAGS_max_body_size
<< " bytes, the connection will be closed."
" Set max_body_size to allow bigger messages";
return result;
}
// Clear context before trying next protocol which definitely has
// an incompatible context with the current one.
if (m->parsing_context()) {
m->reset_parsing_context(NULL);
}
// Try other protocols.
}
return MakeParseError(PARSE_ERROR_TRY_OTHERS);
}