簡體   English   中英

將結構復制到 C 中的結構數組的正確方法

[英]Correct way to copy structs to struct array in C

我想使用 C 中的 libpcap 庫檢查 TCP 數據包的重新傳輸。 根據我的研究,推斷數據包是否是重傳的唯一方法,我需要訪問以前的流量行為,因為單個數據包不足以得出這個結論。

所以我解決問題的方法如下:

這是一個 MRE,它讀取 pcap 文件並分析 IPv4 上的任何 TCP 數據包(如果找到)。

#include <pcap.h>
#include <stdio.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <net/ethernet.h>

void process_packet(u_char *,const struct pcap_pkthdr * , const u_char *);
void find_retransmissions(const u_char * , int );

int main()
{
    pcap_t *handle;
    char errbuff[PCAP_ERRBUF_SIZE];
    handle = pcap_open_offline("smallFlows.pcap", errbuff);
    pcap_loop(handle, -1, process_packet, NULL);
}

void process_packet(u_char *args,const struct pcap_pkthdr * header, const u_char *buffer)
{
    int size = header->len;
    struct ethhdr *eth = (struct ethhdr *)buffer;
    if(eth->h_proto == 8) //Check if IPv4
    {
        struct iphdr *iph = (struct iphdr*)(buffer +sizeof(struct ethhdr));
        if(iph->protocol == 6) //Check if TCP
        {
             find_retransmissions(buffer,size);
        }
    }
    
}

find_retransmissions function 中,我創建了兩個 static arrays 的任意長度的結構,以便存儲以前捕獲的可能的重傳數據包並使用它們來查找頭。

void find_retransmissions(const u_char * Buffer, int Size)
{
    static struct iphdr * previous_packets[20000];
    static struct tcphdr * previous_tcp[20000];
    static int index = 0;
    int retransmission = 0;
    unsigned short iphdrlen;
    
    struct iphdr *iph = (struct iphdr *)(Buffer  + sizeof(struct ethhdr));
    previous_packets[index] = malloc(sizeof(struct iphdr));
    *previous_packets[index] = *iph;
    iphdrlen =iph->ihl*4;

    struct tcphdr *tcph=(struct tcphdr*)(Buffer + iphdrlen + sizeof(struct ethhdr));
    previous_tcp[index]= malloc(sizeof(struct tcphdr));
    *previous_tcp[index]=*tcph;
     index++;
   
    for(int i=0;i<index-1;i++)
    {
        if ((previous_packets[i]->saddr == iph->saddr) && (previous_packets[i]->daddr == iph->daddr)
            && (previous_packets[i]->protocol == iph->protocol))
        {
            if((previous_tcp[i]->source == tcph->source) && (previous_tcp[i]->dest == tcph->dest)
                && (previous_tcp[i]->th_seq == tcph->th_seq))
            {
                retransmission = 1;
                break;
            }
        }
    }
    if (retransmission == 1)
    {
        printf("Retransmission: True");
    }
}

使用此處找到的名為“smallFlows.pcap”的 pcap 文件。

我很確定這種方法對於做這樣的事情來說不僅僅是次優的,而且我也願意接受關於如何解決這個問題的新建議。 我認為我從調試中了解到,我的代碼當前的問題是在*previous_packets[index] = *iph;行中。 *previous_tcp[index]=*tcph; 我的“深度”結構復制方法失敗了,我認為源結構被分別覆蓋了previous_packetsprevious_tcp arrays 的所有元素。 所以我的實際問題是,如何可靠地將找到的數據包頭結構復制到這些 arrays? 我嘗試了更多方法來處理我在 SO 中找到的深層結構副本,但無濟於事。

特定的 pcap 包含大約 120 次 TCP 重傳(用wireshark檢查)。

在評論中解決這個問題:
“可以在c中動態分配一個數組”

由於我沒有確切的結構定義,讓我使用您所描述的近似值來說明如何“可以在 c 中動態分配數組” ,從而提供“結構數組而不是帶有指向結構的指針的數組” 我要說明的方法實際上不是數組本身,但在概念上是一樣的。 它實際上是分配的連續 memory 段,在這種情況下專用於struct20000個實例。

我將在這些示例中引入typedef ,但這是您可以選擇使用或不使用的選項,它不是必需的......

給定以下示例:

//following defines typedef of struct that can be used to create single instances or pointer instances that can be dynamically allocated to whatever size you need


typedef struct {
  ...
} iphdr_s; 

現在,例如,您可以更改此行:

static struct iphdr * previous_packets[20000];

對此:

static iphdr_s *iphdr = malloc(20000*sizeof(*iphdr));
if(!iphdr)
{
    //handle error 
}

當在某些時候不再需要iphdr時,只需釋放它:

free(iphdr);

如果對此改編有疑問,請評論我。

編輯
在評論中解決有關使用普通struct array和動態分配的指向數組的指針以及將元素從兩種類型中的一種復制到另一種的問題:

下面是一個簡單的演示:

typedef struct {
    int val;
} array_s;

int main()//-7,8,6,88,2,-7,10,-5
{
    
    array_s arr1[] = {1,2,3,4};//normal array
    array_s *arr2 = malloc(10*sizeof(*arr2));//pointer to allocated memory
    if(arr2)
    {
        for(int i=0;i<10;i++)
        {
            arr2[i].val = i+1;
        }
        arr1[3] = arr2[7];//copy element from allocated to normal array
    }
    array_s *arr3 = malloc(10*sizeof(*arr3));
    if(arr3)
    {
        arr3[0] = arr2[7];//copy element from allocated to allocated array           
    }
    
    printf("%d\n", arr1[3].val);
    printf("%d\n", arr3[0].val);
    

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM