-
Notifications
You must be signed in to change notification settings - Fork 0
/
customprotocol.h
168 lines (149 loc) · 5.81 KB
/
customprotocol.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include "bcf.h"
using namespace std;
using namespace bcf;
#define WHAT_NAME 0x0001
#define ACTION_GET_NAME 0x0010
#define ACTION_SET_NAME 0x0020
static bcf::PackMode customPackMode = static_cast<bcf::PackMode>(bcf::PackMode::UNPACK_BY_USER + 1);
/**
* @brief
* 下面的例子中演示了如何自定义自己的协议,如果你不想使用bcf内置的支持的协议,你可以参考@ref examples/customprotocol/customprotocol.h 定义自己的通信协议。
* 在下面的例子中,我们参考@class ByHeadProtocolModel,只是将cmd拆分为2个2byte的字段,将body的内容用json格式代替。
* 其实大多数用户层协议都是这个格式,例子的目的只是告诉使用者如何自定义和自定义的要求。
* @note bcf要求报文中【协议类型】和【会话唯一序列号】必须存在,且位于开头,seq后面的内容可以自定义 @see bcf::ByHeadProtocolModel
*/
class CustomProtocolModel : public bcf::AbstractProtocolModel
{
public:
bcf::PackMode protocolType() override
{
return customPackMode;
};
/**
* bcf要求【协议类型】和【会话唯一序列号】必须存在,seq后面的内容可以自定义 @see bcf::ByHeadProtocolModel
* 协议类型\会话唯一序列号\业务类型\当前业务类型下的对应的具体操作\body长度
* |*****************head****************************|*****body*****|
* | type | seq | what | action | length | XXX |
* | 1byte | 4byte | 2byte | 2byte | 4bytes | length bytes |
* |*************************************************|**************|
**/
uint16_t what = 0;
uint16_t action = 0;
uint32_t length = 0;
constexpr static uint16_t body_offset = sizeof(type) + sizeof(seq) + sizeof(what) + sizeof(
action) + sizeof(length);
void setBody(const std::string& body)
{
m_body = body;
length = m_body.length();
}
const std::string& body()
{
return m_body;
};
private:
std::string m_body;
};
class CustomProtocolBuilder : public bcf::IProtocolBuilder
{
public:
CustomProtocolBuilder(bcf::PackEndian endian = bcf::PackEndian::USE_BIG_ENDIAN): IProtocolBuilder(
endian) {};
public:
bcf::PackMode getType()const override
{
return customPackMode;
};
std::shared_ptr<bb::ByteBuffer> build(const std::shared_ptr<bcf::AbstractProtocolModel>& _model)
override
{
//your build... e.g. ByHeadProtocolBuilder
auto model = std::dynamic_pointer_cast<CustomProtocolModel>(_model);
if (nullptr == model) {
return nullptr;
}
uint8_t type = getType();
uint32_t bigSeq = model->seq;
uint16_t bigWhat = model->what;
uint16_t bigAction = model->action;
uint32_t bigLen = model->length;
if (m_endian == bcf::PackEndian::USE_BIG_ENDIAN) {
bigSeq = htobe32(model->seq);
bigWhat = htobe16(model->what);
bigAction = htobe16(model->action);
bigLen = htobe32(model->length);
} else if (m_endian == bcf::PackEndian::USE_LITTEL_ENDIAN) {
bigSeq = htole32(model->seq);
bigWhat = htole16(model->what);
bigAction = htole16(model->action);
bigLen = htole32(model->length);
}
auto ptr = std::make_shared<bb::ByteBuffer>(model->body().length() + model->body_offset);
ptr->put(type);
ptr->putInt(bigSeq);
ptr->putShort(bigWhat);
ptr->putShort(bigAction);
ptr->putInt(bigLen);
ptr->putBytes((uint8_t*)model->body().c_str(), model->body().length());
#ifndef NDEBUG
ptr->printHex();
#endif
return ptr;
};
};
class CustomProtocolParser : public bcf::IProtocolParser
{
public:
CustomProtocolParser(bcf::PackEndian endian = bcf::PackEndian::USE_BIG_ENDIAN): IProtocolParser(
endian) {};
bcf::PackMode getType()const override
{
return customPackMode;
};
void parse(const
std::function<void(ParserState, std::shared_ptr<bcf::AbstractProtocolModel>)>& callback)
override
{
auto model = std::make_shared<CustomProtocolModel>();
//your parse... e.g. ByHeadProtocolParser
int totalLength = m_buffer->size();
if (totalLength < bcf::ByHeadProtocolModel::body_offset) {
std::cout << "totalLength:" << totalLength << "<" << bcf::ByHeadProtocolModel::body_offset <<
std::endl;
return;
}
uint8_t type = m_buffer->getChar();
uint32_t seq = m_buffer->getInt();
uint16_t what = m_buffer->getShort();
uint16_t action = m_buffer->getShort();
uint32_t bodylength = m_buffer->getInt();
if (m_endian == bcf::PackEndian::USE_BIG_ENDIAN) {
seq = be32toh(seq);
what = be16toh(what);
action = be16toh(action);
bodylength = be32toh(bodylength);
} else if (m_endian == bcf::PackEndian::USE_LITTEL_ENDIAN) {
seq = le32toh(seq);
what = le16toh(what);
action = le16toh(action);
bodylength = le32toh(bodylength);
}
const int reqTotalLength = bcf::ByHeadProtocolModel::body_offset + bodylength;
if (totalLength < reqTotalLength) {
std::cout << "totalLength < " << reqTotalLength;
return;
}
bb::ByteBuffer body = m_buffer->mid(bodylength);
model->type = type;
model->seq = seq;
model->what = what;
model->action = action;
model->setBody(std::string(body.begin(), body.end()));
callback(ParserState::OK, model);
if (0 == m_buffer->bytesRemaining()) {
m_buffer->clear();
return;
}
parse(callback);
};
};