talk is cheap;Later equals never;
阿新 • • 發佈:2018-12-13
前言
當讀取離線檔案並分析時,用回撥方式有點不好.
在一個java-cm中看到人家的處理 :只要要分析的資料不夠了,直接去網路上收包(即使就讀1位元組,如果緩衝區內沒有了,也去收一個完整包下來),然後快取起來給呼叫者使用。這就沒有挎包的繁瑣處理了。
因為包資料的處理是在回撥中完成的, 如果在回撥中還想要處理更多的後續包,那是不可能的(只有出了回撥,才會有新的回撥來)。
看了libpcap介面,有pcap_next或pcap_next_ex, 對這個介面進行了封裝,使程式處理流程合理了。當想處理更多資料時,直接去pcap流中去拿,然後緩衝起來。當要處理的資料長度在緩衝區裡有時,就從緩衝區裡拿。如果呼叫方需要的資料長度在緩衝中不夠了,再去pcap流中去拿,然後拼在原有緩衝後面。再將請求的資料返回給呼叫者。
這個類還要再封裝下,要應對從一堆有序的pcap檔案裡順序讀取資料的情況。因為小概率情況,會在不同pcap檔案介面的地方,分析錯誤(如果資料沒有無縫讀取的話)。
demo下載
稍後上傳
demo預覽
// @file main.cpp // @brief 無縫從pcap流中連續讀取資料 #include <iostream> #include "IF_pcap_byte_stream.h" // #define WORK_ON_COMPANY #ifdef WORK_ON_COMPANY #else // #ifdef WORK_ON_COMPANY #define OFFLINE_PCAP_FILE_TO_PARSE "D:\\pcap_files\\test.pcap" #define MY_CAPTRUE_FILTER "host 192.168.11.132 and port 6666" #define DB_IP_TO_PARSE "192.168.11.132" #define DB_PORT_TO_PARSE 1521 #endif // #ifdef WORK_ON_COMPANY #ifndef MYLOG_I #define MYLOG_I printf #endif // #ifndef MYLOG_I #ifndef LINE_80 #define LINE_80 "--------------------------------------------------------------------------------" #endif // #ifndef LINE_80 IF_pcap_byte_stream g_my_pcap_stream; BOOL WINAPI phandler_routine(DWORD CtrlType); int main() { bool rc = false; int i = 0; int err = 0; u_char uc_tmp = '\0'; int i_cb_pos_index = 0; do { if (!fn_dy_load_wpcap()) { break; } if (!SetConsoleCtrlHandler(phandler_routine, TRUE)) { break; } if (!g_my_pcap_stream.open_pcap_file(OFFLINE_PCAP_FILE_TO_PARSE, MY_CAPTRUE_FILTER)) { printf("open pcap file error\n"); break; } while (g_my_pcap_stream.read_n_bytes(&uc_tmp, sizeof(uc_tmp))) { printf("bytes[%d] = 0x%X\n", i_cb_pos_index, uc_tmp); i_cb_pos_index++; } printf("task over\n"); rc = true; } while (0); if (!rc) { printf("error happen\n"); } g_my_pcap_stream.close_pcap_file(); system("pause"); return 0; } BOOL WINAPI phandler_routine(DWORD CtrlType) { BOOL rc = FALSE; switch (CtrlType) { case CTRL_C_EVENT: { g_my_pcap_stream.close_pcap_file(); } rc = TRUE; break; default: break; } return rc; }
// @file \read_from_pcap_files\IF_pcap_byte_stream.h // @brief 構造一個邏輯, 讓'從pcap包中讀取位元組'像從一個連續的流中讀取一樣 // 不用再考慮挎包問題 #ifndef __IF_PCAP_BYTE_STREAM_H__ #define __IF_PCAP_BYTE_STREAM_H__ #include "wpcap_dll_ex.h" class IF_pcap_byte_stream { public: IF_pcap_byte_stream(); virtual ~IF_pcap_byte_stream(); bool open_pcap_file(const char* psz_pcap_flie_path_name, const char* psz_captrue_filter); void close_pcap_file(); // 讀失敗的可能性 // * 離線檔案開啟失敗 // * 離線檔案讀完了 bool read_n_bytes(/*OUT*/ u_char* puc_buf, /*IN*/ int cb_to_read); private: int get_packet_buf_left_len(); // 得到緩衝區內包內容生於長度 int get_packet_buf_free_size(); // 得到緩衝區還能放多少位元組 void move_left_data_to_buf_head(); // 如果要附加新的包資料進來, 先將剩下的資料挪到緩衝區的開始處 bool append_data_to_buf(const u_char* pkt_data, int i_len); //向當前緩衝區內附加包資料 private: pcap_t* m_h_lib_pcap; struct bpf_program m_bpf_program; bool m_b_valid_bpf; u_char m_packet_buf[1024 * 16]; // 能裝下2個包的緩衝區 int m_i_packet_buf_pos_begin; // 包緩衝區內有效內容的開始位置 int m_i_packet_buf_pos_end; // 包緩衝區內有效內容的結束位置 // 如果 (m_i_packet_buf_pos_begin == m_i_packet_buf_pos_end), 說明緩衝區內是空的 }; #endif // #ifndef __IF_PCAP_BYTE_STREAM_H__
// @file read_from_pcap_files\IF_pcap_byte_stream.cpp
#include "IF_pcap_byte_stream.h"
IF_pcap_byte_stream::IF_pcap_byte_stream()
{
m_h_lib_pcap = NULL;
m_b_valid_bpf = false;
memset(&m_bpf_program, 0, sizeof(struct bpf_program));
memset(m_packet_buf, 0, sizeof(m_packet_buf));
m_i_packet_buf_pos_begin = 0;
m_i_packet_buf_pos_end = 0;
}
IF_pcap_byte_stream::~IF_pcap_byte_stream()
{
close_pcap_file();
}
bool IF_pcap_byte_stream::open_pcap_file(const char* psz_pcap_flie_path_name, const char* psz_captrue_filter)
{
bool b_rc = false;
char errbuf[PCAP_ERRBUF_SIZE] = { '\0' };
do {
if (NULL == psz_pcap_flie_path_name) {
break;
}
close_pcap_file();
m_h_lib_pcap = pcap_open_offline(psz_pcap_flie_path_name, errbuf);
if (NULL == m_h_lib_pcap) {
break;
}
pcap_set_promisc(m_h_lib_pcap, 1); // interface_opts->promisc_mode is 1
pcap_set_timeout(m_h_lib_pcap, -1); // timeout is 250
pcap_set_buffer_size(m_h_lib_pcap, 10 * 1024 * 1024);
// capture_loop_init_filter
int snaplen = pcap_snapshot(m_h_lib_pcap);
// printf("snaplen = %d\n", snaplen);
// compile BPF
if (pcap_compile(m_h_lib_pcap, &m_bpf_program, psz_captrue_filter, 1, 0) == -1) {
fprintf(stderr, "error\n");
break;
}
m_b_valid_bpf = true;
// set BPF filter
if (pcap_setfilter(m_h_lib_pcap, &m_bpf_program) == -1) {
fprintf(stderr, "error\n");
break;
}
b_rc = true;
} while (0);
return b_rc;
}
void IF_pcap_byte_stream::close_pcap_file()
{
if (m_b_valid_bpf) {
m_b_valid_bpf = false;
pcap_freecode(&m_bpf_program);
}
if (NULL != m_h_lib_pcap) {
pcap_close(m_h_lib_pcap);
m_h_lib_pcap = NULL;
}
}
bool IF_pcap_byte_stream::read_n_bytes(/*OUT*/ u_char* puc_buf, /*IN*/ int cb_to_read)
{
bool b_rc = false;
pcap_pkthdr* p_pkt_hdr = NULL;
const u_char* p_pkt_data = NULL;
int i_rc = 0;
do {
if (NULL == m_h_lib_pcap) {
break; // pcap file not open, or open failed
}
if (get_packet_buf_left_len() < cb_to_read) {
i_rc = pcap_next_ex(m_h_lib_pcap, &p_pkt_hdr, &p_pkt_data);
if (1 != i_rc) {
// 0 是超時
// -2 是離線檔案讀完了
break;
}
move_left_data_to_buf_head();
if (get_packet_buf_free_size() < (int)p_pkt_hdr->caplen) {
break; // 緩衝區開小了
}
if (!append_data_to_buf(p_pkt_data, p_pkt_hdr->caplen)) {
break; // 生於的緩衝區空間不夠大
}
}
if (get_packet_buf_left_len() >= cb_to_read) {
memcpy(puc_buf, m_packet_buf + m_i_packet_buf_pos_begin, cb_to_read);
m_i_packet_buf_pos_begin += cb_to_read;
b_rc = true;
}
} while (0);
return b_rc;
}
bool IF_pcap_byte_stream::append_data_to_buf(const u_char* pkt_data, int i_len)
{
bool b_rc = false;
do {
if (get_packet_buf_free_size() < i_len) {
break;
}
memcpy(m_packet_buf, pkt_data, i_len);
m_i_packet_buf_pos_end += i_len;
b_rc = true;
} while (0);
return b_rc;
}
int IF_pcap_byte_stream::get_packet_buf_left_len()
{
if (m_i_packet_buf_pos_end > m_i_packet_buf_pos_begin) {
return (m_i_packet_buf_pos_end - m_i_packet_buf_pos_begin);
}
return 0;
}
void IF_pcap_byte_stream::move_left_data_to_buf_head()
{
int i_left_data_len = 0;
int i = 0;
u_char* pdst = NULL;
u_char* psrc = NULL;
if (m_i_packet_buf_pos_begin != 0) {
pdst = m_packet_buf;
psrc = m_packet_buf + m_i_packet_buf_pos_begin;
i_left_data_len = get_packet_buf_left_len();
if ((m_i_packet_buf_pos_begin + 1) > i_left_data_len) {
// 直接拷貝過去
memcpy(pdst, psrc, i_left_data_len);
} else {
// 資料有重疊, 逐位元組拷貝過去
for (i = 0; i < i_left_data_len; i++) {
pdst[i] = psrc[i];
}
}
m_i_packet_buf_pos_begin = 0;
m_i_packet_buf_pos_end = i_left_data_len;
}
}
int IF_pcap_byte_stream::get_packet_buf_free_size()
{
return (sizeof(m_packet_buf) - m_i_packet_buf_pos_end);
}