【发布时间】:2020-01-13 21:12:36
【问题描述】:
在我们的任务中,我们必须构建自己的 TCP 处理程序(提供了框架)。我现在必须收集所有 TCP 段并将它们存储到一个向量中,以便在收到最后一个段后重新组合流,并将其转发到下一层(例如 HTTP)。
为此,我们必须实现void handle_packet()。在我们的框架中,有几个结构和类应该“帮助”我们。
这是我迄今为止提出的:
tcp.h
#include <iostream>
#include <cstdint>
#include <vector>
#include <netinet/tcp.h> // struct tcphdr
using Header = struct tcphdr;
struct Segment {
const Header * hdr;
uint8_t payload[];
};
struct Stream {
std::vector<Segment> segments;
void add_segment(Segment new_segment);
};
void Stream::add_segment(Segment new_segment) {
segments.push_back(new_segment);
// testing: print all sequence numbers of each segment
for(size_t i = 0; i < segments.size(); i++)
std::cout << ntohl(segments[i].hdr->seq) << std::endl;
}
class Protocol {
private:
Stream streams;
public:
void handle_packet(const Header* tcp_segment_hdr, uint8_t* tcp_payload, size_t tcp_payload_len);
};
tcp.cpp
#include "tcp.h"
void handle_packet(const Header* tcp_segment_hdr, uint8_t* tcp_payload, size_t tcp_payload_len) {
// "struct hack" to copy content
Segment* segment = reinterpret_cast<Segment *>(malloc(sizeof(struct Segment) + buffer_len * sizeof(uint8_t)) );
// store the header
segment->hdr = tcp_segment_hdr; // add the header
// store the payload
for(size_t i = 0; i < tcp_payload_len; i++)
segment->payload[i] = tcp_payload[i];
streams.add_segment(*segment);
free(segment);
}
我正在使用“struct hack”将标头和有效负载复制到 Segment * 结构中(这是我想出的唯一可行的方法)。之后,我将新段存储到streams(类Protocol 的成员)成员变量vector<Segments>。然后我释放内存。
之后我想看看是否所有内容都存储在segments 中(出于测试目的,我尝试打印段的每个序列号) - 它不是......
但是,大小仍然正确。
我想这是因为我free'd 之后在handle_packet() 中的结构,这也影响了我在std::vector<Segment>segments 中的条目。但是我怎样才能使条目仍然在那里而没有任何内存泄漏?我用谷歌搜索但没有找到令人满意的解决方案如何解决我的问题。
任何帮助表示赞赏! 谢谢
编辑:我在 AddressSanitizer 中也收到以下错误:
==22658==ERROR: AddressSanitizer: stack-buffer-overflow on address
0x7fff5288b66c at pc 0x559511b2f7bc bp 0x7fff5288b2b0 sp 0x7fff5288b2a0
WRITE of size 1 at 0x7fff5288b66c thread T0
在 IPv4 中,我们有以下结构:
struct Fragment : public std::vector<uint8_t> {
using std::vector<uint8_t>::vector;
const Header *getHeader() { return (const Header *)data(); }
};
但我没有做那部分,因为我不知道如何“填充”这些值并添加一个条目。有什么想法可以采用struct Fragment 到struct Segment 并填充/添加(持久)值吗?
编辑 2: 作为临时结果,我为有效负载提供了固定大小 (1500) 并删除了“struct hack”并将其编辑回简单的 Segment segment。
编辑 3: 好的,即使是固定大小,它仍然无法正常工作..
编辑 4:我找到了一个可行的解决方案!不过,我会在星期六(截止日期之后)描述我的解决方案,以避免抄袭。
【问题讨论】:
-
请注意
uint8_t payload[];不是标准 C++ 并且您的代码不是可移植的。 -
还有其他标准的 C++ 方式吗?如果是,你能举个例子吗?我只是想使用这些结构,因为它们已经存在了。
-
结构破解是唯一的工作方式??
Segment segment;呢?木已成舟。问题不在于复制Segment,问题在于当将它们推入Stream中的向量时,您只是在做数据的浅拷贝。 -
@s.r.这样做的 C++ 方法是将
std::vector<uint8_t>作为payload的类型。这样做虽然需要更多的序列化,因为您需要传输其大小,以便接收器可以在将缓冲区复制到向量之前分配正确的空间量。另一件事是硬编码payload的大小,但这会限制您并且会浪费空间。 -
最接近你将在 C++ 中获得的东西(不会徘徊在怪异的土地上)是 @NathanOliver 在上面提出的。没有完全连续的数据结构可以做到这一点。即使在 C 中,如果您使用数组尝试此操作,它也会失败。你需要一个链接结构。
标签: c++ vector struct tcp malloc