This commit is contained in:
Saturneric 2021-03-11 16:06:57 +08:00
parent abeb88b481
commit e9b667da26
5 changed files with 86 additions and 4 deletions

View File

@ -15,6 +15,7 @@ using std::queue;
namespace Net {
// the structure to store the option part of a message
class Option {
public:
Option(const string &key, const string &value);
@ -34,6 +35,7 @@ public:
void updateValue(const string &value);
private:
// the key is unique within a message
shared_ptr<string> key;
shared_ptr<string> value;
};
@ -105,30 +107,45 @@ private:
ssize_t decode_tail(const vector<char> &raw_Data, size_t offset, Message &msg);
void calculate_options_hash(const vector<char> &raw_data, int32_t end_index, int16_t &sum_hash);
SHA256Generator sign_gen;
};
class MessageParser {
public:
// send a received buffer to parse
void parse(const void *buf, size_t size);
// Get a parsed message from the queue
shared_ptr<Message> getMessage();
// Get the count of the parsed meaasge
size_t getMessageCount();
private:
// state recorder of a special part of a message
int head_state = -5;
int option_state = -4;
ssize_t body_state = -1;
int tail_state = -4;
// factory used to read data and form the message step by step
MessageFactory factory;
// store the message parsed
queue<shared_ptr<Message>> msgs;
// buffer to store the data give by
queue<char> buffer;
// buffer to temporarily store the data of the certain part related to the state of the parser
vector<char> temp_buffer;
// temporarily record the message concentrated
shared_ptr<Message> temp_msg;
// reset all state and refresh the parser
void reset_state();
void locate_head();

Binary file not shown.

View File

@ -2,6 +2,7 @@
#include "communicate/message.h"
#include <stdexcept>
#include <stdio.h>
namespace Net {
@ -24,18 +25,21 @@ void MessageFactory::encode_head(const Message &msg, vector<char> &raw_data) {
raw_data.push_back(' ');
// 协议版本
const string s_version = std::to_string(msg.version);
raw_data.insert(raw_data.end(), s_version.cbegin(), s_version.cend());
raw_data.push_back(' ');
// 消息类型
const string s_type = std::to_string(msg.type);
raw_data.insert(raw_data.end(), s_type.cbegin(), s_type.cend());
raw_data.push_back(' ');
// 会话ID
const string s_tid = std::to_string(msg.tid);
raw_data.insert(raw_data.end(), s_tid.cbegin(), s_tid.cend());
@ -67,6 +71,16 @@ void MessageFactory::encode_options(const Message &msg,
raw_data.push_back('\n');
}
// 计算头部和配置部分的哈希值
int16_t sum_hash;
calculate_options_hash(raw_data, raw_data.size() - 1, sum_hash);
const string sum_hash_str = std::to_string(sum_hash);
raw_data.insert(raw_data.end(), sum_hash_str.cbegin(), sum_hash_str.cend());
raw_data.push_back('\r');
raw_data.push_back('\n');
raw_data.push_back('\r');
raw_data.push_back('\n');
}
@ -158,8 +172,26 @@ ssize_t MessageFactory::decode_options(const vector<char> &raw_data,
msg.addOption(key.c_str(), value.c_str());
}
int sum_hash_range = index - 2;
--index;
string sum_hash_str;
while((c = raw_data[index++]) != '\r') {
sum_hash_str.push_back(c);
}
if(raw_data[index++] != '\n') {
return -1;
}
int16_t sum_hash = std::stoi(sum_hash_str);
int16_t sum_hash_check;
calculate_options_hash(raw_data, sum_hash_range, sum_hash_check);
if(sum_hash_check != sum_hash) return -1;
if (raw_data[index++] != '\r' || raw_data[index++] != '\n')
return -1;
@ -200,6 +232,24 @@ ssize_t MessageFactory::decode_tail(const vector<char> &raw_data, size_t offset,
return index;
}
void MessageFactory::calculate_options_hash(const vector<char> &raw_data, int32_t end_index, int16_t &sum_hash) {
if(end_index > raw_data.size()) {
throw std::runtime_error("end index out of range");
}
sum_hash = 0;
int32_t index = 0;
for(auto &c : raw_data) {
sum_hash += static_cast<int16_t>(c);
sum_hash %= 65535;
if (index++ >= end_index) break;
}
}
bool MessageFactory::decodeMessage(const vector<char> &raw_data, Message &msg) {
msg.clear();
@ -251,4 +301,5 @@ bool MessageFactory::decodeMessageTail(const vector<char> &raw_data, Message &ms
if(!~decode_tail(raw_data, 0, msg)) return false;
return true;
}
} // namespace Net

View File

@ -6,12 +6,16 @@ namespace Net {
void MessageParser::parse(const void *buf, size_t size) {
// push all data in buff into queue named buffer
const char *c_buf = (const char *)buf;
for (int i = 0; i < size; i++) {
buffer.push(c_buf[i]);
}
// process the data byte by byte until the queue is empty
while(!buffer.empty()) {
// if there is no message concentrated then create new message
if (temp_msg == nullptr) {
temp_msg = std::make_shared<Message>();
}
@ -26,9 +30,12 @@ void MessageParser::parse(const void *buf, size_t size) {
locate_tail();
}
// tail processing done
if(!tail_state){
// release the message concentrated
msgs.push(temp_msg);
temp_msg = nullptr;
// reset the state of the parser
reset_state();
}
}
@ -91,6 +98,8 @@ void MessageParser::locate_option() {
option_state++;
else if(c == '\r')
option_state = -1;
else if (c > 47 && c < 58)
option_state++;
continue;
}
if(option_state == -3) {
@ -219,8 +228,10 @@ void MessageParser::locate_tail() {
void MessageParser::reset_state() {
temp_buffer.clear();
// reset the message concentrated
if(temp_msg != nullptr)
temp_msg->clear();
// reset the state recorder
head_state = -5;
option_state = -4;
body_state = -1;

View File

@ -26,6 +26,11 @@ TEST(Message_Test, base_test_1) {
mf.encodeMessage(msg, rd);
PrintTools::printInfoBuffer(rd, "Message Raw Data");
for(auto &c : rd) {
printf("%c", c);
}
printf("\n");
ASSERT_TRUE(mf.decodeMessage(rd, msg));
ASSERT_EQ(msg.getTID(), 1);
@ -55,8 +60,6 @@ TEST(MessageParser_Test, base_test_1) {
MessageParser mp;
mp.parse(rd.data(), rd.size());
printf("SIZE: %lu\n", rd.size());
ASSERT_EQ(mp.getMessageCount(), 1);
shared_ptr<Message> p_msg = mp.getMessage();