一、 下载及编译libpcap
1) 在网上下载libpcap,我下载的是libpcap-1.8.1.tar.gz,
2) 解压缩,执行tar xvzf libpcap-1.8.1.tar.gz
3) cd到libpcap-1.8.1目录,打开configure文件,将下面三行注释掉:
- #if test -z “KaTeX parse error: Expected 'EOF', got '&' at position 12: with_pcap" &̲& test "cross_compiling” = yes; then
{ { echo “ a s m e : as_me: asme:LINENO: error: pcap type not determined when cross-compiling; use --with-pcap=…” >&5
#fi
4) 执行sudo ./configure --host=arm-linux --with-pcap=linux 生成Makefile文件
如果在生成Makefile过程出现以下问题:
Your operating system’s lex is insufficient to compile libpcap
安装:yum -y install flex 、 yum -y install bison 、sudo apt-get install flex
5) 如果第四步执行成功,会生成一个Makefile文件,将Makefile文件中:
CC=gcc改成CC=arm-linux-gcc
6)make,完成之后会生成两个库文件编译完成后在libpcap-1.8.1目录里面会生成libpcap.a静态库和libpcap.so.1.8.1动态库。这两个库就是我们所需要的
7)在x86编译程序时加上-lpcap连接libpcap库,
8)将libpcap.so.1.8.1拷到arm板上/lib中,再建立两个软连接
In -s libpcap.so.1.8.1 libpcap.so.1
In -s libpcap.so.1 libpcap.so
二、 libpcap库使用
1) 函数名称:char *pcap_lookupdev(char *errbuf)
函数功能:用于返回可被pcap_open_live()或pcap_lookupnet()函数调用的网络设备名指针。参数说明:如果函数出错,则返回NULL,同时errbuf中存放相关的错误消息。
2)函数名称:pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char ebuf)
函数功能:获得用于捕获网络数据包的数据包捕获描述字。
参数说明:device 参数为指定打开的网络设备名。snaplen参数定义捕获数据的最大字 节数。promisc指定是否将网络接口置于混杂模式。to_ms参数指定超时时 间(毫秒)。ebuf参数则仅在pcap_open_live()函数出错返回NULL时用于传递错误消息。
3)函数名称:pcap_dumper_t *pcap_dump_open(pcap_t *p, char *fname)
函数功能:打开用于保存捕获数据包的文件,用于写入。
参数说明:fname 参数为”-“时表示标准输出。出错时返回NULL。p参数为调用pcap_open_offline()或pcap_open_live()函数后返回的 pcap结构指针。fname参数指定打开的文件名。如果返回NULL,则可调用pcap_geterr()函数获取错误消息。
4)函数名称:int pcap_loop(pcap_t *p, int cnt,pcap_handler callback, u_char *user)
函数功能: 功能基本与pcap_dispatch()函数相同,只不过此函数在cnt个数据包被处理或出现错误时才返回,但读取超时不会返回。而如果为 pcap_open_live()函数指定了一个非零值的超时设置,然后调用pcap_dispatch()函数,则当超时发生时 pcap_dispatch()函数会返回。cnt参数为负值时pcap_loop()函数将始终循环运行,除非出现错误。
5)函数名称:void pcap_dump(u_char *user, struct pcap_pkthdr *h,u_char *sp)
函数功能:向调用pcap_dump_open()函数打开的文件输出一个数据包。该函数可作为pcap_dispatch()函数的回调函数。
6)函数名称:void pcap_dump_close(pcap_dumper_t *p)
函数功能:关闭相应的被打开文件。
在Ags310程序上就只用到以上几个函数,之前的ags310程序对lidar数据的接收处理是:先开辟一个缓冲区,把从recvfrom函数收的数据拷贝到缓冲区中,对lidar数据存盘处理:先从缓冲区中读出来,然后再写到文件中去。
现在Ags310的程序是利用pcap_loop()函数进行循环抓包,抓到包之后跳用回调函数,在回调函数将数据写入(pcap_dump)文件中,写入2001024包之后,关闭文件再新建一个 这个方案的结果就是写人文件(同时写SD和EMMC)204800包需要146s,理论时间是122.2s,出现丢包很严重。
这个方案经过实际验证实行不的,我们的开发板是Cortex-A5的,工作频率最高500MHZ,雷神16线激光雷达的数据是0.6ms一包,一包是1248个字节,大概就是2M/s的数据,在程序开辟一个大的缓冲区,等收到3000包,就写一次文件*
部分程序
devstr = pcap_lookupdev(errBuf); //找到一个网络设备,返回一个char型针针
if(devstr)
{
printf("success:device :%s/n",devstr);
}
m_pHandle = pcap_open_live(devstr,65535,1,0,errBuf);//打开一个网络设备,返回捕获网络数据包的描述字
if(!m_pHandle)
{
printf("error:pcap_open_live():%s\n",errBuf);
}
char pszFilepath[MAX_PATH] = {0};
sprintf(pszFilepath,"/mnt/sd/lidar_%d.pcap",m_nFileIndex);
m_pDumpOpen = pcap_dump_open(m_pHandle,pszFilepath);//打开一个.pcap文件,返回文件描述符
pcap_loop(pThis->m_pHandle,-1,getPacket,(u_char *)&id); //循环抓包
回调函数**
void CLidarProcess::getPacket(u_char *args,const struct pcap_pkthdr *pkthdr,const u_char *packet)
{
static i4 i4RecvCount = 0;
g_bLidarNetRecvStatusFlag = true;
if(true == g_bPPSGetGpsTimeFlag) //是否同步
{
if(DEFAULT_PACAP_PACK_NUM <= m_pLidarProcess->m_PcakNum)
{ //判断是否超过200*1024个包
struct tm *p;
struct timeval current_cpu_time;
gettimeofday(¤t_cpu_time, NULL);
p = gmtime(&(current_cpu_time.tv_sec));
m_nFileIndex++; //文件索引加1
m_pLidarProcess->m_PcakNum = 0; //包数清零
pcap_dump_close(m_pLidarProcess->m_pDumpOpen);//关闭文件
m_pLidarProcess->m_pDumpOpen = NULL;
char pszFilePath[MAX_PATH] = {0};
sprintf(pszFilePath,"/mnt/sd/lidar_%d%02d%02d%02d%02d%02d_%d.pcap",(1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec,m_nFileIndex);
m_pLidarProcess->m_pDumpOpen= pcap_dump_open(m_pLidarProcess->m_pHandle,pszFilePath);//重新打开一个文件
if(NULL == m_pLidarProcess->m_pDumpOpen)
{
printf("open file failed\n");
return ;
}
}
pcap_dump((u_char *)m_pLidarProcess->m_pDumpOpen,pkthdr,packet);//将数据包写入文件中
m_pLidarProcess->m_PcakNum++; //包数加1
}
关于libpcap库函数的详细解释请参考博客:
https://blog.csdn.net/u012592081/article/details/47047237