本文共 2891 字,大约阅读时间需要 9 分钟。
问题背景:公司原来为了搜索局域网内的网络视频解码器开发了一个Decoder Finder,用的是UDP广播的方式。现在韩国的客户发现当IP地址和PC不在同一网段时,无法搜索到decoder,人家还找了一个他们的软件,暴强,就算是IP地址全是0,照搜不误。
问题分析:
PC端,其实也就是用,直接和网卡通信,把消息包发出来,并且在接受响应。这样数据包不经过IP和UDP协议栈,IP地址有效无效都无所谓了。发送消息的时候,把目的MAC填为全F,做成广播包。
嵌入式端,操作系统式uCLinux,使用AF_PACKET协议簇,RAW_SOCKET类型的端口即可和网卡驱动直接通信,绕过IP以上的协议栈。基础知识可参考和。
以太网的侦结构如下:
-----------------------------------------------------
| 目的地址
问题解决:
1.Linux下直接从网卡接收数据
非常简单的。当然,前提条件是Linux内核配置中,已经包含了PACKET SOCKET的支持。
要记得,我们后面面对的数据,就是以太网一级的。
INT32 SockFd;
//第一个参数,协议簇,填写PF_PACKET
//第二个参数,填写SOCK_RAW,表明这是原始socket,这样数据包就不会经过协议栈的处理了。
//第三个参数,希望接受到的消息类型。参考If_ether.h中的协议定义。这里实际上也可以自己定义。
//它表明了上层协议的类型(注意,我们现在是在直接和网卡打交道)。
//内核会去判断消息头里面的类型,如果匹配,就往应用层发,如果不匹配,就不发。
//ETH_P_ALL表示不管什么类型的协议都往应用层发。
SockFd = socket(PF_PACKET, SOCK_RAW, htons(VSTRONG_PROTOCOL));
if (-1 == SockFd) {
char
//不绑定网卡,不绑定地址,来了的数据包都接收
i32Len = recvfrom(SockFd, szBuff, sizeof(szBuff), 0, NULL, NULL); if ( i32Len < 14 ) {
你可能会说,不对啊,网卡看到目的MAC和自己的MAC不匹配,就不会接收消数据啊。
的确是这样的,如果要收到不是发给自己的数据包,还得将网卡设置为混杂模式。但是
也有例外,一是目的MAC地址为全F的情况,视为广播地址,网卡看到全F的地址会处理的;
另外就是组播的情况。如上所述,我们是在PC端发搜索消息时,用了广播地址。
小结一下:数据的流通过程就是:
PC发消息(应用层)--》PC的网卡-----》Decoder的网卡(判断是广播地址)----》驱动程序-----》内核(判断是ROW SOCKET,跳过协议栈的处理)----》应用程序
=============================================================================================
2.Linux下直接从网卡发送数据
发送的时候,也是要用户自己构造数据帧,另外还需要填写一个地址数据。
#include <linux/if_packet.h> #include <linux/if.h>
#include <sys/ioctl.h>
struct sockaddr_ll stTagAddr;
memset(&stTagAddr, 0 , sizeof(stTagAddr)); stTagAddr.sll_family
//填写目标MAC地址 stTagAddr.sll_addr[0]
//填充帧头和内容
i32Len = sendto(SockFd, (INT8 *)szbuff, sizeof(szbuff), 0, (const struct sockaddr *)&stTagAddr, sizeof(stTagAddr));
可以用ethereal抓包看看你发出来的数据是否正确。另外,如果你的数据不足46字节(不含帧头)Linux的网卡驱动程序会把数据补0凑足46个字节,接收端处理时应当注意。
发送过程小结:应用程序(选定用来发送数据包的网卡)----》内核-----》网卡驱动程序-----》网卡---》PC的网卡----》winpcap-----》PC的应用程序。
转载地址:http://lmhvi.baihongyu.com/