-
Notifications
You must be signed in to change notification settings - Fork 1
/
codec.cpp
executable file
·174 lines (158 loc) · 4.65 KB
/
codec.cpp
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
169
170
171
172
173
174
#include "codec.h"
#include <muduo/base/Logging.h>
#include <memory>
#include <zlib.h> // adler32
#include <arpa/inet.h> // htonl, ntohl
using namespace std;
Codec::Codec()
{
}
int asInt32(const char* buf)
{
int be32 = 0;
::memcpy(&be32, buf, sizeof(be32));
return ::ntohl(be32);
}
/**
* @brief Codec::parse 解析数据
* @param socketfd
* @param inputBuffer
*/
void Codec::parse(int socketfd,muduo::net::Buffer *inputBuffer)
{
while (inputBuffer->readableBytes() >= kMinMessageLen + kHeaderLen)
{
const int len = inputBuffer->peekInt32();
if (len < kMinMessageLen)
{
LOG_ERROR<<"parse protobuf error:invalid length";
break;
}
else if (inputBuffer->readableBytes() >= muduo::implicit_cast<size_t>(len + kHeaderLen))
{
MessagePtr message = parse_aux(inputBuffer->peek()+kHeaderLen,len);
if (message)
{
inputBuffer->retrieve(kHeaderLen+len);
dispatch(socketfd,message);
}
else
{
LOG_ERROR<<"parse protobuf error";
break;
}
}
else
{
break;
}
}
}
/**
* @brief Codec::parse_aux //解析数据得到相应的Message
* @param buf 消息字符串,长度信息已被跳过
* @param len 消息长度
* @return
*/
MessagePtr Codec::parse_aux(const char* buf, int len)
{
MessagePtr message;
// check sum
int expectedCheckSum = asInt32(buf + len - kHeaderLen);
int checkSum = static_cast<int>(
::adler32(1,
reinterpret_cast<const Bytef*>(buf),
static_cast<int>(len - kHeaderLen)));
if (checkSum == expectedCheckSum)
{
// get message type name
int nameLen = asInt32(buf);
if (nameLen >= 2 && nameLen <= len - 2*kHeaderLen)
{
std::string typeName(buf + kHeaderLen, buf + kHeaderLen + nameLen - 1);
// create message object
message.reset(createMessage(typeName));
if (message)
{
// parse from buffer
const char* data = buf + kHeaderLen + nameLen;
int dataLen = len - nameLen - 2*kHeaderLen;
if (!message->ParseFromArray(data, dataLen))
{
LOG_ERROR<<"ParseError";
}
}
else
{
LOG_ERROR<<"UnownMessageType";
}
}
else
{
LOG_ERROR<<"InvalidNameLen";
}
}
else
{
LOG_ERROR<<"CheckSumError";
}
return message;
}
void Codec::dispatch(int socketfd, MessagePtr message)
{
auto it = callbackMap.find(message->GetDescriptor());
if (it != callbackMap.end())
{
it->second->onMessage(socketfd, message);
}
else
LOG_ERROR<<message->GetTypeName()<<"didn't register callback";
}
/**
* @brief Codec::encode 将要发送的信息打包
* @param message 要发送的信息
* @return 如果message.AppendToString失败则返回空字符串
*/
string Codec::enCode(const google::protobuf::Message& message)
{
string result;
result.resize(kHeaderLen);
const string& typeName = message.GetTypeName();
int32_t nameLen = static_cast<int32_t>(typeName.size()+1);
int32_t be32 = ::htonl(nameLen);
result.append(reinterpret_cast<char*>(&be32), sizeof be32);
result.append(typeName.c_str(), nameLen);
bool succeed = message.AppendToString(&result);
if (succeed)
{
const char* begin = result.c_str() + kHeaderLen;
int32_t checkSum = adler32(1, reinterpret_cast<const Bytef*>(begin), result.size()-kHeaderLen);
int32_t be32 = ::htonl(checkSum);
result.append(reinterpret_cast<char*>(&be32), sizeof be32);
int32_t len = ::htonl(result.size() - kHeaderLen);
std::copy(reinterpret_cast<char*>(&len),
reinterpret_cast<char*>(&len) + sizeof len,
result.begin());
}
else
{
result.clear();
}
return result;
}
google::protobuf::Message* Codec::createMessage(const std::string& typeName)
{
google::protobuf::Message* message = NULL;
const google::protobuf::Descriptor* descriptor =
google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(typeName);
if (descriptor)
{
const google::protobuf::Message* prototype =
google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
if (prototype)
{
message = prototype->New();
}
}
return message;
}