【问题标题】:Store allocated struct (using the "struct hack") in std::vector在 std::vector 中存储分配的结构(使用“struct hack”)
【发布时间】: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&lt;Segments&gt;。然后我释放内存。

之后我想看看是否所有内容都存储在segments 中(出于测试目的,我尝试打印段的每个序列号) - 它不是...... 但是,大小仍然正确。

我想这是因为我free'd 之后在handle_packet() 中的结构,这也影响了我在std::vector&lt;Segment&gt;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 Fragmentstruct Segment 并填充/添加(持久)值吗?

编辑 2: 作为临时结果,我为有效负载提供了固定大小 (1500) 并删除了“struct hack”并将其编辑回简单的 Segment segment

编辑 3: 好的,即使是固定大小,它仍然无法正常工作..

编辑 4:我找到了一个可行的解决方案!不过,我会在星期六(截止日期之后)描述我的解决方案,以避免抄袭。

【问题讨论】:

  • 请注意uint8_t payload[]; 不是标准 C++ 并且您的代码不是可移植的。
  • 还有其他标准的 C++ 方式吗?如果是,你能举个例子吗?我只是想使用这些结构,因为它们已经存在了。
  • 结构破解是唯一的工作方式?? Segment segment; 呢?木已成舟。问题不在于复制Segment,问题在于当将它们推入Stream 中的向量时,您只是在做数据的浅拷贝。
  • @s.r.这样做的 C++ 方法是将std::vector&lt;uint8_t&gt; 作为payload 的类型。这样做虽然需要更多的序列化,因为您需要传输其大小,以便接收器可以在将缓冲区复制到向量之前分配正确的空间量。另一件事是硬编码payload 的大小,但这会限制您并且会浪费空间。
  • 最接近你将在 C++ 中获得的东西(不会徘徊在怪异的土地上)是 @NathanOliver 在上面提出的。没有完全连续的数据结构可以做到这一点。即使在 C 中,如果您使用数组尝试此操作,它也会失败。你需要一个链接结构。

标签: c++ vector struct tcp malloc


【解决方案1】:

正如所承诺的,这是我的解决方案。我采用了以下结构定义:

/**
* Container for a segment of a TCP stream.
*/
struct Segment : public std::vector<uint8_t> {
    using std::vector<uint8_t>::vector; 
};

segment 数据复制到我所做的结构中:

Segment segment;

// fill the segment with the data
for(unsigned int i = 0; i < buffer_len; i++)
  segment.push_back(buffer[i]);

要访问数据,您可以使用来自std::vector 的已定义data() 成员(结构继承自该成员)。我还有另一个 struct Stream 和一个名为 Segment allSegments 的成员,其中每个 segment 都被添加(总共所有段)。结果访问如下所示:

for(unsigned int i = 0; i < allSegments.size(); i++)
{
  for(unsigned int j = 0; j < allSegments[i].size(); j++)
    printf( "%x",allSegments[i].data()[j] );
}

我不知道你可以继承std::vectorstruct Segment 是我们的学习助理预先定义的,不是我自己实现的。起初我不知道如何访问数据并想实现一种不同的方式 - 这就是我提出 struct hack 的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多