检查缓冲区中的重复数组

时间:2018-09-11 07:57:17

标签: c arrays duplicates

我正在一个嵌入式系统上工作,如果设备无法建立通信,则会在其中保存数据包。我有很多可以保存数据包的方案,但我想避免保存重复的软件包。

系统的数据包长16个字节,我将它们存储在320个字节的缓冲区中(以便最多保留20个数据包)。

如何检查要保存的数据包是否在缓冲区的某处重复?

2 个答案:

答案 0 :(得分:0)

只需循环浏览已保存的数据包,然后将其与要添加的新数据包进行比较

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>

// represents a 16 char packet
typedef char packet_t[16];

/* pktbuf library - used to store up to 20 packet_t packets */

struct pktbuf_s {
    packet_t buffer[20];
    size_t packetcnt;
};

#define PKTBUF_INIT()  {0}

int pktbuf_save(struct pktbuf_s *t, packet_t *packet)
{
    assert(t != NULL);
    assert(packet != NULL);
    for (size_t i = 0; i < t->packetcnt; ++i) {
        if (!memcmp(&t->buffer[i], packet, sizeof(*packet))) {
            // duplicate packet found in buffer, notify user application
            return 1;
        }
    }
    if (t->packetcnt == sizeof(t->buffer)/sizeof(*t->buffer)) {
        // no place in buffer, notify user
        return -1;
    }
    // save the packet and increment packet count
    memcpy(&t->buffer[t->packetcnt], packet, sizeof(*packet));
    t->packetcnt++;
    // succcess
    return 0;
}

void pktbuf_clear(struct pktbuf_s *t)
{
    assert(t != NULL);
    t->packetcnt = 0;
}

size_t pktbuf_get(struct pktbuf_s *t, packet_t **packets)
{
    assert(t != NULL);
    *packets = t->buffer;
    return t->packetcnt;
}

/* User application example ----------------------------------- */

void packet_receive(packet_t *packet)
{
    memset(packet, 1, sizeof(*packet));
}

int main()
{
    struct pktbuf_s pktbuf = PKTBUF_INIT();

    // some user app receives packet
    packet_t packet;
    packet_receive(&packet);
    // save received packet in bnuffer
    if (pktbuf_save(&pktbuf, &packet) == -1) {
        // no place in buffer to save the packet
        // print error message? blink with the led? or just ignore?
    }
    // continue the user application, until we want to...

    // drain packet buffer
    packet_t *packets;
    const size_t packetscnt = pktbuf_get(&pktbuf, &packets);
    for (size_t i = 0; i < packetscnt; ++i) {
        // do smth with packet: packets[i]
    }
    // clear buffered packets
    pktbuf_clear(&pktbuf);

    // continue with user application

    return 0;
}

答案 1 :(得分:0)

数据包标识符/序列号

在不知道数据包结构或预期目的的情况下很难给出相关建议。例如,这是RS485网络吗?与单个设备进行UART通信?还有吗?

但是,如果您可以控制数据包的结构,则可以使用数据包标识符序列号。如果仅与一台设备通信,则仅此一项就足以区分数据包。数据包结构可能类似于以下内容。此处的相关字段是 seq no。(序列号)。数字表示字节偏移。

0         1         2     3      15
---------------------------------------------------
| control | seq no. | len | data | checksum / crc |
---------------------------------------------------
           ^^^^^^^^^

如果有多个设备,则您的数据包可能包含源和地址字段。在这种情况下,地址信息和数据包标识符的组合就足够了。

0         1         2        3        4     5      15
---------------------------------------------------------------------
| control | seq no. | source | dest   | len | data | checksum / crc |
---------------------------------------------------------------------
           ^^^^^^^^^^^^^^^^^^

将在生成数据包的设备上承担责任,以增加每个新数据包的序号。由于您的缓冲区只能容纳20个数据包,因此1字节的ID /序列字段可能就足够了。

(序列号也可以用于其他目的,例如检查数据包是否在传输过程中丢失-在这种情况下,接收到的数据包的序列号中会有一个“空白”。)

很难知道这种优化是否必要-或使用简单的memcmp()比较数据包是否足够。