首先来介绍下以太帧理论:
以太帧是包含MAC帧的,先看下MAC帧:
目的地址:接收帧的网络适配器的物理地址(MAC地址);
源地址:发送帧的网络适配器的物理地址(MAC地址);
类型:上层协议的类型。在处理数据时必须设置该字段,表示数据交付给哪个协议处理,如0x0800,表示交付给IP协议。
数据:表示交付给上一层的数据,以太帧最小为46字节,最大为15000,不足46字节会自动填充。
FCS帧校验序列:检测该帧是否出错,为4个字节。接收方会程序计算CRC,然后与FCS进行对比,一样则没问题。不一样,则丢弃。
从mac层到物理层会添加前同步码:用来使接收端的适配器在MAC帧时能够迅速调整时钟频率,使得它和发送方相同。前同步码为7字节。
帧开始定位符:帧的启初符,1字节,前6为0和1交替,后2个为连续的1,告诉适配器,帧来了。
实践:
源码如下:
pro
QT -= gui
CONFIG += c++11 console
CONFIG -= app_bundle
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
main.cpp
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
INCLUDEPATH += D:/winscp/WpdPack/Include
LIBS += -L D:/winscp/WpdPack/Lib/libpacket.a \
-L D:/winscp/WpdPack/Lib/libwpcap.a
main.cpp
#define HAVE_REMOTE
#include <QCoreApplication>
#include <QDebug>
#include "pcap.h"
#include "remote-ext.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString devName;
//获取网卡
pcap_if_t *allDevs;
char errbuf[PCAP_ERRBUF_SIZE];
if(pcap_findalldevs(&allDevs, errbuf) == -1){
qDebug() << "error:" << errbuf;
return 0;
}
devName = allDevs->name;
pcap_freealldevs(allDevs);
//打卡网卡
pcap_t *fp;
u_char packet[100];
if((fp= pcap_open(devName.toStdString().c_str(), 100, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf)) == NULL){
qDebug() << "error:" << errbuf;
return 0;
}
packet[0]=1;
packet[1]=1;
packet[2]=1;
packet[3]=1;
packet[4]=1;
packet[5]=1;
packet[6]=2;
packet[7]=2;
packet[8]=2;
packet[9]=2;
packet[10]=2;
packet[11]=2;
for(int i = 12; i < 100; i++){
packet[i]=0xFF;
}
if(pcap_sendpacket(fp, packet, 100) != 0){
qDebug() << "send error:" << pcap_geterr(fp);
return 0;
}
qDebug() << "over";
return a.exec();
}
抓包如下:
可见其以太帧:
目的mac:01:01:01:01:01:01 6 * 8=48位
源mac:02:02:02:02:02:02 6 * 8=48位
类型:ff ff 2 * 8=16位
下面就是数据位了。
源码打包下载地址:
https://github.com/fengfanchen/Qt/tree/master/EthernetNetWork