其实这块我除了查阅网上文章,主要还是参考了三家(米联客、正点原子、黑金)的教程,里面写的也非常详细了,可以自己去三家搜索看看,互为对照。
PS:刚刚查的时候没找着米联客和黑金的在哪了。。就以正点原子的为参考说说个人见解。
以下图片均来自于正点原子文档:
一般都会先给个OSI模型,但其实这都比较抽象,咱们主要是想知道FPGA给PC发了啥数,能让PC那边认为是收到的UDP数据。
所以我都倾向于直接看这个图,里面其实就几个信息需要拆解,按层分的话:
1.MAC层:1.1 前导码是什么、1.2 SFD是什么、1.3 以太网帧头是什么、1.4 FCS是什么?1.5 MAC层数据段跟IP层啥关系?
2.IP层:2.1 IP首部是什么、2.2 IP层数据段和UDP层什么关系?
3.UDP层:3.1 UDP首部是什么、3.2 UDP层数据段和用户数据什么关系?
4.用户数据层:这个没啥疑问,就是想发的数据内容。
1.1 前导码
因为mac层在最低端,他就等同于硬件往外输出01信号的数据源了,所以他要包含一些与业务无关、而是保证传输正确的内容。
前导码就是其中一个,他负责实现数据同步,就定死了是7个字节同步码组成(55-55-55-55-55-55-55),因为8‘h55其实就是8'b0101_0101,就是给底层硬件输出提供一堆0和1交替的数据。
1.2 SFD(帧起始界符)
前面前导码完成了数据同步,接下来就是确定一帧的开始。SFD就是负责表示一帧的开始,他固定为0xd5。
1.3 以太网帧头
以太网帧头就由目的MAC地址+源MAC地址+长度/类型来组成了,稍微多一些概念。
目的MAC地址:假设A设备发送UDP数据到B设备,目的MAC地址就是B设备的MAC地址;
源MAC地址:源MAC地址就是A设备的MAC地址;
查询MAC地址:百度搜搜,一般linux 在cmd写ifconfig、windows写ipconfig就行了。
长度/类型:是两种可能性,如果大于0x0600,就代表类型(0x0800代表IP、0x0806代表ARP);如果小于0x0600就是数据段长度;一般都是表示类型(0x0800);
1.4 FCS
CRC校验码,详细可以再去搜搜,一般用的是CRC-32标准。
1.5 MAC层数据段跟IP层的关系
MAC层数据段= IP层首部+IP层数据段 (IP层数据段=UDP层首部+UDP层数据段(UDP层数据段=用户数据))
2.1 IP首部
IP首部就是20个字节+可选字段,上面这个图按一行32bit(4字节),共5行理解就行,一般没有可选字段。
第一个字节(0-3bit)是版本,一般都固定,IPv4就是0100,IPv6就是0110。
第二个字节(4-7bit)是首部长度,就是IP首部长度有多少个32bit(4字节),没有可选字段的时候就是20个字节,这里的值也就是20/4=5(0101).
服务类型:详细解释可以再搜索看看,目前一般是全零。
总长度:就是IP首部加上IP数据部分的字节数量。总长度有16bit表示,所以可以表征65535个字节的长度,但一般数据没那么长。
标识字符:16位标识字段,自增的,每发一个报文就加一。
标志:一般3’h2;
片偏移:一般13'h000;
生存时间:一般填64(8‘h40);
协议:ICMP为1(8'h01),TCP为6(8’h06),UDP为17(8‘h11);
首部校验和:只校验数据报的首部,不包含数据段;
源IP地址:A发UDP给B,A的IP地址是源IP地址;
目的IP地址:A发UDP给B,B的IP地址是目的IP地址;
最后填下来就是下面的形式:
2.2 IP层数据段跟UDP层的关系
IP层数据段=UDP层首部+UDP层数据段
3.1 UDP首部
UDP格式比IP简单
1.源端口号:这个一般自己定义就行,如果就一个UDP发送的话,就随意填写;
2.目的端口号:这个就看接收端那边选择哪个端口收UDP;
3.UDP长度:包含UDP首部长度+数据长度,单位是字节;
4.UDP校验和:一般接收端不检测UDP检验和,有需要再自己搜搜;
3.2 UDP层数据段跟用户数据的关系
UDP层数据段=用户数据
所以上面MAC层+IP层+UDP层整个汇总下来,格式如下(都是连在一起的):
字节数 | 7 | 1 | 14 | ||
大模块 | 前导码 | SFD | 以太网帧头 | ||
字节数 | 7 | 1 | 6 | 6 | 2 |
描述 | 前导码 | SFD | 目的MAC | 源MAC | 长度/类型 |
内容 | 55-55-55-55-55-55-55 | d5 | 12:34:56:78 | 22:33:44:55 | 0800(IP) |
字节数 | 8 | N | 4 | |||
大模块 | UDP首部 | FCS | ||||
字节数 | 2 | 2 | 2 | 2 | N | 4 |
描述 | 源端口号 | 目的端口号 | UDP长度 | UDP校验和 | 用户数据 | FCS |
内容 | 8'h01 | 8'h01 | N+8 | 8'hXX | xx | 16'hxxxx |
crc32 |
最开始给参数的时候可以照着上面的表给,后续有别的协议或格式再考虑增加模块。
此外,还需注意:
1.一般UDP长度和IP长度、校验和这些部分的计算,在开源代码里都做好了,到时候只要记得接上即可。
2.出问题时可以用wireshark 或者tcpdump命令抓包看看,一般问题都出在1.FCS校验错误导致接收端网卡丢包、2.以太网帧头里的类型不正确、IP首部中的协议不正确;3.目的IP、目的MAC不正确。
别的暂时想不到了,后续会对github的代码进行分析,然后根据代码搭建仿真,展示一个完整的udp协议实现的仿真案例。