mmap的使用及pcap文件解析示例

mmap能夠通過將磁盤上的文件映射到內存中,通過指針訪問文件內容。這樣能夠達到快速處理文件。

包含的頭文件爲#include <sys/mman.h>,主要使用的函數有:

//打開文件,獲取文件描述符

int open(const char *pathname, int flags);

//獲取文件字節數

int stat(const char *restrict path, struct stat *restrict buf);

//使用mmap將對應的文件映射到本進程內存 

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);   

//解除隱射才能釋放內存空間

int munmap(void *addr, size_t length);

//關閉文件

 int close(int fd);


注意:

使用完mmap之後,要記得使用munmap函數釋放內存空間,否則就會產生內存泄露,而且此內存泄露不易發現,使用valgrind也沒能查出來。


以下以我處理pcap文件的函數爲例,展示mmap的使用方法,示例代碼片段如下:



#include <sys/mman.h>
#include <sys/stat.h>
#include <pcap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int parseAPcapfile(char * file_name) {
    struct pcap_pkthdr pkt_hdr;
    struct eth_hdr ethhdr;
    struct ip_hdr iphdr;

    struct stat statbuf;
    long file_size;
    int i;
    int pcap_fd;
    char *origin_data, *data, *flow_ptr;

    //get file description
    /* file open failed. return FILE_OPEN_ERROR. */
    pcap_fd = open(file_name, O_RDONLY);
    if(-1 == pcap_fd){
            printf("ERROR:file open error!\n");
            return FILE_OPEN_ERROR;
        }

    //get file bytes
    //file_size = lseek(pcap_fd, 0, SEEK_END);
    stat(file_name,&statbuf);
    file_size = statbuf.st_size;
    if(file_size < 24) {
        close(pcap_fd);
        printf("pcap file is damaged!\n");
        return FILE_DAMAGED;
    }

    //get mmap pointer
    origin_data = (char *)mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, pcap_fd, 0);
    data = origin_data;

    printf("file size is: %ld\n", file_size);
    //if(strlen(data) < 24 ||  0xA1B2C3D4 != *(uint32_t*)data) {
    if(0xA1B2C3D4 != *(uint32_t*)data) {
        printf("read pcap failed: invailied file magic: %x\n", *(uint32_t*)data);
        munmap(origin_data, file_size);
        origin_data = NULL;
        data = NULL;
        close(pcap_fd);
        return FILE_MAGIC_ERROR;
    }
    data += 24;
    while (data - origin_data < file_size) {
        /*
         * start to parse a flow
         * get a start pointer of a flow
         */
        flow_ptr = data;
        /*
         * parse the pcap header of a flow
         */
        pkt_hdr.ts.tv_sec = *(uint32_t *)flow_ptr;
        flow_ptr += 4;
        pkt_hdr.ts.tv_usec = *(uint32_t *)flow_ptr;
        flow_ptr += 4;
        pkt_hdr.caplen = *(uint32_t *)flow_ptr;
        flow_ptr += 4;
        pkt_hdr.len = *(uint32_t *)flow_ptr;
        flow_ptr += 4;
        //Print PCAP header
        //printPcapHeader(pkt_hdr);

        /*
         * Start to parse a flow that captured from network interface
         * no need to convert to host sequence: MAC address/ string /uint8_t
         * need to convert to host sequence: uint16_t<ntohs()>/ uint32_t<ntohl()>
         *
         * parse the Ethernet header of a flow
         */
        ethhdr = *(struct eth_hdr*)flow_ptr;
        flow_ptr += ETHERNET_HEADER_LEN;
        //print ethernet information
        //printEthHeader(ethhdr);

        //if proto is not IP proto, then continue.
        if(ntohs(ethhdr.proto) != ETH_P_IP) {
            //next flow
            printf("the flow is not ip proto\n");
            data += (pkt_hdr.caplen + 16);
            continue;
        }

        /*
         * Start to parse the IP header
         * get the ip header
         */
        iphdr = *(struct ip_hdr *)flow_ptr;
        // print the ip header
        //printIpInfo(iphdr);

        parseIpHeader(iphdr);

        //next flow
        data += (pkt_hdr.caplen + 16);
    }

    //free mmap space
    munmap(origin_data, file_size);
    //close file
    close(pcap_fd);
    if (data - origin_data == file_size) {
        printf("have processed  %d bytes data!\n", data - origin_data);
        origin_data = NULL;
        data = NULL;
        return FILE_PROCESS_SUCCESS;
    } else {
        origin_data = NULL;
        data = NULL;
        printf("ERROR: only processed  %d bytes data!\n", data - origin_data);
        return FILE_PROCESS_FAILED;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章