c++ winpcap开发(8)
發送數據包
雖然名稱WinPcap清楚地表明圖書館的目的是分組捕獲,但還提供了其他有用的原始網絡功能。其中,用戶可以找到一組完整的功能來發送數據包。
請注意,原來的libpcap庫目前沒有提供任何方式發送數據包,因此這里顯示的所有功能都是WinPcap擴展,在Unix下不起作用。
用pcap_sendpacket()發送單個數據包
發送數據包的最簡單方式如下面的代碼段所示。打開適配器后,調用pcap_sendpacket()發送手工制作的數據包。pcap_sendpacket()將包含要發送的數據的緩沖區的長度和要發送的緩沖區的適配器作為參數。請注意,緩沖區按原樣發送到網絡,無需任何操作。這意味著應用程序必須創建正確的協議頭以發送有意義的東西。
#include <stdlib.h> #include <stdio.h>#include <pcap.h>void main(int argc, char **argv) { pcap_t *fp; char errbuf[PCAP_ERRBUF_SIZE]; u_char packet[100]; int i;/* Check the validity of the command line */if (argc != 2){printf("usage: %s interface (e.g. 'rpcap://eth0')", argv[0]);return;}/* Open the output device */if ( (fp= pcap_open(argv[1], // name of the device100, // portion of the packet to capture (only the first 100 bytes)PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode1000, // read timeoutNULL, // authentication on the remote machineerrbuf // error buffer) ) == NULL){fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", argv[1]);return;}/* Supposing to be on ethernet, set mac destination to 1:1:1:1:1:1 */packet[0]=1;packet[1]=1;packet[2]=1;packet[3]=1;packet[4]=1;packet[5]=1;/* set mac source to 2:2:2:2:2:2 */packet[6]=2;packet[7]=2;packet[8]=2;packet[9]=2;packet[10]=2;packet[11]=2;/* Fill the rest of the packet */for(i=12;i<100;i++){packet[i]=(u_char)i;}/* Send down the packet */if (pcap_sendpacket(fp, packet, 100 /* size */) != 0){fprintf(stderr,"\nError sending the packet: %s\n", pcap_geterr(fp));return;}return; }發送隊列
雖然pcap_sendpacket()提供了一種簡單而直接的方式來發送單個數據包,但發送隊列提供了高級,強大和優化的機制來發送數據包集合。發送隊列是將發送到網絡的可變數量的數據包的容器。它有一個大小,表示它可以存儲的最大字節數。
創建一個發送隊列,調用pcap_sendqueue_alloc()函數,指定新發送隊列的大小。
創建發送隊列后,可以使用pcap_sendqueue_queue()將數據包添加到發送隊列。此函數使用帶有時間戳和長度的pcap_pkthdr以及數據包的數據的緩沖區。這些參數與pcap_next_ex()和pcap_handler()接收的參數相同,因此排隊剛從文件捕獲或讀取的數據包是將這些參數傳遞給pcap_sendqueue_queue()的問題。
要發送發送隊列,WinPcap提供pcap_sendqueue_transmit()函數。注意第三個參數:如果非零,發送將被同步,即將遵守數據包的相對時間戳。此操作需要大量CPU,因為使用“忙等待”循環在內核驅動程序中進行同步。雖然這個操作是CPU密集型的,但是通常會導致非常高的精度數據包傳輸(通常在幾微秒或更短的時間內)。
請注意,使用pcap_sendqueue_transmit()發送發送隊列比執行一系列pcap_sendpacket()更有效率,因為發送隊列在內核級別緩沖大幅度減少上下文切換的數量。
當不再需要隊列時,可以使用pcap_sendqueue_destroy()刪除它,從而釋放與發送隊列關聯的所有緩沖區。
下一個程序顯示如何使用發送隊列。它使用pcap_open_offline()打開一個捕獲文件,然后將數據包從文件移動到正確分配的發送隊列。在他的點上,它發送隊列,如果用戶請求,則同步它。
請注意,轉儲文件的鏈接層與將使用pcap_datalink()發送數據包的接口進行比較,如果它們不同,則打印警告 - 重要的是捕獲文件鏈接層為與適配器的鏈路層相同,否則傳輸是無意義的。
#include <stdlib.h> #include <stdio.h>#include <pcap.h>void usage();void main(int argc, char **argv) {pcap_t *indesc,*outdesc;char errbuf[PCAP_ERRBUF_SIZE];char source[PCAP_BUF_SIZE];FILE *capfile;int caplen, sync;u_int res;pcap_send_queue *squeue;struct pcap_pkthdr *pktheader;u_char *pktdata;float cpu_time;u_int npacks = 0;errno_t fopen_error;/* Check the validity of the command line */if (argc <= 2 || argc >= 5){usage();return;}/* Retrieve the length of the capture file */fopen_error = fopen_s(&capfile, argv[1],"rb");if(fopen_error != 0){printf("Error opening the file, errno %d.\n", fopen_error);return;}fseek(capfile , 0, SEEK_END);caplen= ftell(capfile)- sizeof(struct pcap_file_header);fclose(capfile);/* Chek if the timestamps must be respected */if(argc == 4 && argv[3][0] == 's')sync = TRUE;elsesync = FALSE;/* Open the capture *//* Create the source string according to the new WinPcap syntax */if ( pcap_createsrcstr( source, // variable that will keep the source stringPCAP_SRC_FILE, // we want to open a fileNULL, // remote hostNULL, // port on the remote hostargv[1], // name of the file we want to openerrbuf // error buffer) != 0){fprintf(stderr,"\nError creating a source string\n");return;}/* Open the capture file */if ( (indesc= pcap_open(source, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf) ) == NULL){fprintf(stderr,"\nUnable to open the file %s.\n", source);return;}/* Open the output adapter */if ( (outdesc= pcap_open(argv[2], 100, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf) ) == NULL){fprintf(stderr,"\nUnable to open adapter %s.\n", source);return;}/* Check the MAC type */if (pcap_datalink(indesc) != pcap_datalink(outdesc)){printf("Warning: the datalink of the capture differs from the one of the selected interface.\n");printf("Press a key to continue, or CTRL+C to stop.\n");getchar();}/* Allocate a send queue */squeue = pcap_sendqueue_alloc(caplen);/* Fill the queue with the packets from the file */while ((res = pcap_next_ex( indesc, &pktheader, &pktdata)) == 1){if (pcap_sendqueue_queue(squeue, pktheader, pktdata) == -1){printf("Warning: packet buffer too small, not all the packets will be sent.\n");break;}npacks++;}if (res == -1){printf("Corrupted input file.\n");pcap_sendqueue_destroy(squeue);return;}/* Transmit the queue */cpu_time = (float)clock ();if ((res = pcap_sendqueue_transmit(outdesc, squeue, sync)) < squeue->len){printf("An error occurred sending the packets: %s. Only %d bytes were sent\n", pcap_geterr(outdesc), res);}cpu_time = (clock() - cpu_time)/CLK_TCK;printf ("\n\nElapsed time: %5.3f\n", cpu_time);printf ("\nTotal packets generated = %d", npacks);printf ("\nAverage packets per second = %d", (int)((double)npacks/cpu_time));printf ("\n");/* free the send queue */pcap_sendqueue_destroy(squeue);/* Close the input file */pcap_close(indesc);/* * lose the output adapter * IMPORTANT: remember to close the adapter, otherwise there will be no guarantee that all the * packets will be sent!*/pcap_close(outdesc);return; }void usage() {printf("\nSendcap, sends a libpcap/tcpdump capture file to the net. Copyright (C) 2002 Loris Degioanni.\n");printf("\nUsage:\n");printf("\t sendcap file_name adapter [s]\n");printf("\nParameters:\n");printf("\nfile_name: the name of the dump file that will be sent to the network\n");printf("\nadapter: the device to use. Use \"WinDump -D\" for a list of valid devices\n");printf("\ns: if present, forces the packets to be sent synchronously, i.e. respecting the timestamps in the dump file. This option will work only under Windows NTx.\n\n");exit(0); }總結
以上是生活随笔為你收集整理的c++ winpcap开发(8)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mac 上安装服务,查看服务,重启和关闭
- 下一篇: Windows cmd命令反斜杠问题