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;
}
}