是否可以使用for循环索引访问结构的元素?

时间:2018-07-23 12:24:23

标签: c structure packet

我试图通过用户输入来形成一个IP数据包。我只做到L4。 l7标头,包括我作为字符串的数据。对于L4标头,用户必须提供l4不同字段的值,我尝试将它们转换为字符串并追加到数据包。我也想为第3层做类似的事情。

它工作正常,但是在代码中,我最终为L4的不同字段编写了类似的代码。我在代码块中提到了它们。可以使用for循环将所有4个块转换为单个块。

代码部分是:

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

typedef struct l4{
    unsigned short source_port;
    unsigned short dest_port;
    unsigned int length;
    unsigned short checksum;
}l4_struct;

void append_l7(char *packet , FILE *fp) {
    char l7_packet[255];
    fscanf(fp , "%[^\n]%*c" , l7_packet);
    strcpy(packet , l7_packet);
}

void append_l4(char *packet , FILE *fp) {
    char l4_header_string[255] , buf[255];
    memset(buf  , 0 ,  255);
    l4_struct l4_header;

//block 1
    fscanf(fp , "%hd" , &l4_header.source_port);
    sprintf(buf , "%x" , l4_header.source_port);
    strcpy(l4_header_string , buf);
    memset(buf  , 0 ,  255);

//block 2
    fscanf(fp , "%hd" , &l4_header.dest_port);
    sprintf(buf , "%s %.4x" , l4_header_string , l4_header.dest_port);
    strcpy(l4_header_string , buf);
    memset(buf  , 0 ,  255);

//block 3
    fscanf(fp , "%d" , &l4_header.length);
    sprintf(buf , "%s %.4x" , l4_header_string , l4_header.length);
    strcpy(l4_header_string , buf);
    memset(buf  , 0 ,  255);

//block 4
    fscanf(fp , "%hd" , &l4_header.checksum);
    sprintf(buf , "%s %.4x" , l4_header_string , l4_header.checksum);
    strcpy(l4_header_string , buf);
    memset(buf  , 0 ,  255);

//    strcat(l4_header_string , packet);
    sprintf(buf , "%s %s" , l4_header_string , packet);
    strcpy(packet , buf);
}

void append_l3(char *packet , FILE *fp) {

}

int main() {
    FILE *fp = fopen("input_packet.txt" , "r");
    int packet_size = 255; //We can take from user also
    char *packet = (char *)calloc(packet_size , sizeof(char));

    append_l7(packet  , fp);
    append_l4(packet , fp);
//    append_l3(packet , fp);

    //printing packet
    printf("\nPacket:%s\n" , packet);
//    printf("%hd\n%d\n" , sizeof(unsigned short) , sizeof(unsigned int));
    free(fp);
    free(packet);
}

input_packet.txt是

ab c9 01 00 00 01 00 00 00 00 00 00 09 6d 63 63 6c 65 6c 6c 61 6e 02 63 73 05 6d 69 61 6d 69 03 65 64 75 00 00 01 00 01
58759
53
48
58144

输出:

Packet:e587 0035 0030 e320 ab c9 01 00 00 01 00 00 00 00 00 00 09 6d 63 63 6c 65 6c 6c 61 6e 02 63 73 05 6d 69 61 6d 69 03 65 64 75 00 00 01 00 01

我希望 append_l4()功能如下:

char **dptr = (char **) malloc(sizeof(char *) * 4);
dptr[0] = "source_port";
dptr[1] = "dest_port";
dptr[2] = "length";
dptr[3] = "checksum";

void append_l4(char *packet , FILE *fp) {
    char l4_header_string[255] , buf[255];
    memset(buf  , 0 ,  255);
    l4_struct l4_header;

    for(i = 0; i < 4; i++){
        fscanf(fp , "%(this type varies)" , &l4_header.dptr[i]);
        sprintf(buf , "%s %.4x" , l4_header_string , l4_header.dptr[i]);
        strcpy(l4_header_string , buf);
        memset(buf  , 0 ,  255);
    }

//    strcat(l4_header_string , packet);
    sprintf(buf , "%s %s" , l4_header_string , packet);
    strcpy(packet , buf);
}

有可能吗?如果是,请建议我如何实现此目标。

Iterating over a struct in C++与之类似,但它在C ++中。

2 个答案:

答案 0 :(得分:0)

我的建议是您尝试使用union,这将允许您将“不同”的数据类型存储在同一存储位置。但是,您必须针对所有可能的field大小(似乎正是您想要的大小)平等地处理输入数据。我自己完成了构建TCP数据包的工作,以下结构非常有用(特别是用于复制操作)。

union packet_u
{
  uint8_t a[__TOTAL_STRUCT_SIZE__];
  struct
  {
      uint16_t field1;
      uint16_t field2;
      uint32_t field3;
      uint16_t field4;
  }
};

读取输入文件并将其保存在您的结构中应该很简单,所以我将让您继续研究这个想法。另外,您可以更改要迭代的最小大小(即uint8_t a[...])。

答案 1 :(得分:0)

那snprintf + memcpy + memset(...,0,...)只是胡说八道。创建一个缓冲区,读取该缓冲区,然后从该缓冲区复制到另一个缓冲区,然后将该缓冲区归零...为什么不一直复制到目标缓冲区? snprintf返回写入的字符数,您可以通过操纵其第一个参数的位置来连接其输出:

size_t pos = 0;

pos += sprintf(&l4_header_string[pos], "%x", l4_header.source_port);
pos += sprintf(&l4_header_string[pos], " %.4x", l4_header.<next field>);
pos += sprintf(&l4_header_string[pos], " %.4x", l4_header.<next field>);
pos += sprintf(&l4_header_string[pos], " %.4x", l4_header.<next field>);

无论如何,您只能做一个scanf和一个snprintf:

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

typedef struct l4{
    unsigned short source_port;
    unsigned short dest_port;
    unsigned int length;
    unsigned short checksum;
}l4_struct;

void append_l7(char *packet , FILE *fp) {
    fgets(packet, 255, fp);
}

void append_l4(char *packet , FILE *fp) {
    l4_struct l4_header;

    fscanf(fp , "%hd %hd %d %hd" , 
        &l4_header.source_port,
        &l4_header.dest_port,
        &l4_header.length,
        &l4_header.checksum);
    // we can't snprintf(buffer, "%s", buffer) so we need to create a packet copy
    char *packetcopy = strdup(packet);
    assert(packetcopy != NULL);
    sprintf(packet, "%x %.4x %.4x %.4x %s",
        l4_header.source_port, 
        l4_header.dest_port,
        l4_header.length, 
        l4_header.checksum,
        packetcopy);
    free(packetcopy);
}

int main() {
    FILE *fp = fopen("input_packet.txt" , "r");
    int packet_size = 255; //We can take from user also
    char *packet = (char *)calloc(packet_size , sizeof(char));

    append_l7(packet, fp);
    append_l4(packet, fp);

    printf("Packet:%s\n" , packet);

    // free(fp); ????????
    fclose(fp);
    free(packet);
}