分析TCP/IP协议栈代码之UDP(STM32平台)

发布者:TranquilDreams最新更新时间:2020-11-28 来源: eefocus关键字:TCP  IP协议栈  UDP  STM32平台 手机看文章 扫描二维码
随时随地手机看文章

1. UDP介绍

UDP是一个简单的面向数据报的运输层协议:进程的每个输出操作都正好产生一个 UDP数据报,并组装成一份待发送的IP数据报。这与面向流字符的协议不同,如TCP,应用程序产生的全体数据与真正发送的单个IP数据报可能没有什么联系。


UDP数据报封装成一份 IP数据报的格式如图11 - 1所示。


RFC 768 [Postel 1980] 是UDP的正式规范。


UDP不提供可靠性:它把应用程序传给IP层的数据发送出去,但是并不保证它们能到达目的地。由于缺乏可靠性,我们似乎觉得要避免使用UDP而使用一种可靠协议如TCP。在讨论完TCP后将再回到这个话题,看看什么样的应用程序可以使用UDP。


2. UDP首部

UDP首部的各字段如图11 - 2所示。


端口号表示发送进程和接收进程。在图 1 - 8中,我们画出了TCP和UDP用目的端口号来分用来自IP层的数据的过程。

由于IP层已经把IP数据报分配给TCP或UDP(根据I P首部中协议字段值) ,因此TCP端口号由TCP来查看,而UDP端口号由UDP来查看。TCP端口号与UDP端口号是相互独立的。


尽管相互独立,如果TCP和UDP同时提供某种知名服务,两个协议通常选择相同的端口号。这纯粹是为了使用方便,而不是协议本身的要求。


UDP长度字段指的是UDP首部和UDP数据的字节长度。该字段的最小值为 8字节(发送一份0字节的UDP数据报是OK) 。这个UDP长度是有冗余的。 IP数据报长度指的是数据报全长(图3 - 1) ,因此UDP数据报长度是全长减去IP首部的长度(该值在首部长度字段中指定,如图3 - 1所示)


UDP检验和覆盖UDP首部和UDP数据。回想IP首部的检验和,它只覆盖IP的首部—并不覆盖IP数据报中的任何数据。


UDP和TCP在首部中都有覆盖它们首部和数据的检验和。UDP的检验和是可选的,而TCP的检验和是必需的。


尽管UDP检验和的基本计算方法与我们在描述的IP首部检验和计算方法相类似(16 bit字的二进制反码和, 但是稍微有所不同,在根据字段类型判定为UDP或者TCP时加入了一些处理,看代码就晓得了) ,但是它们之间存在不同的地方。首先, UDP数据报的长度可以为奇数字节,但是检验和算法是把若干个 16 bit字相加。解决方法是必要时在最后增加填充字节0,这只是为了检验和的计算(也就是说,可能增加的填充字节不被传送) 。


其次,UDP数据报和TCP段都包含一个1 2字节长的伪首部( 本TCP/IP协议栈有所不同,只加入了4字节源IP地址和4字节目的IP地址,即利用IP首部的尾巴,实现了空间上的复用,看代码就晓得了),它是为了计算检验和而设置的。伪首部包含IP首部一些字段。其目的是让 UDP两次检查数据是否已经正确到达目的地(例如,IP没有接受地址不是本主机的数据报,以及IP没有把应传给另一高层的数据报传给UDP) 。UDP数据报中的伪首部格式如图11 - 3所示。


在该图中,我们特地举了一个奇数长度的数据报例子,因而在计算检验和时需要加上 填充字节(0)。注意,UDP数据报的长度在检验和计算过程中出现两次。


如果检验和的计算结果为 0,则存入的值为全1(65535) ,这在二进制反码计算中是等效的。如果传送的检验和为0,说明发送端没有计算检验和。( 因为协议要求如此,故代码需要实现之。)如果发送端没有计算检验和而接收端检测到检验和有差错,那么 UDP数据报就要被悄悄地丢弃。不产生任何差错报文(当IP层检测到IP首部检验和有差错时也这样做) 。


UDP检验和是一个端到端的检验和。它由发送端计算,然后由接收端验证。其目的是为了发现UDP首部和数据在发送端到接收端之间发生的任何改动。

/*下面阐述UDP校验和的一些历史和必要性*/

尽管UDP检验和是可选的,但是它们应该总是在用。在 80年代,一些计算机产商在默认条件下关闭UDP检验和的功能,以提高使用UDP协议的NFS(Network File System)的速度。


在单个局域网中这可能是可以接受的,但是在数据报通过路由器时,通过对链路层数据帧进行循环冗余检验(如以太网或令牌环数据帧)可以检测到大多数的差错,导致传输失败。不管相信与否,路由器中也存在软件和硬件差错,以致于修改数据报中的数据。如果关闭端到端的UDP检验和功能,那么这些差错在UDP数据报中就不能被检测出来。另外,一些数据链路层协议(如SLIP)没有任何形式的数据链路检验和。


Host Requirements RFC声明,UDP检验和选项在默认条件下是打开的。它还声明,如果发送端已经计算了检验和,那么接收端必须检验接收到的检验和(如接收到检验和不为0) 。但是,许多系统没有遵守这一点,只是在出口检验和选项被打开时才验证接收到的检验和。


另外需要解释几个术语:  IP数据报是指IP层端到端的传输单元(在分片之前和重新组装之后) , 分组是指在IP层和链路层之间传送的数据单元。一个分组可以是一个完整的 IP数据报,也可以是IP数据报的一个分片。( 这里有如何分片的说明,书里介绍的详细,简而言之,超过MTU就需要分,但是第一片和接下来的片是有区别的:第一个有UDP首部,其他没有,但是可以通过IP的flags来组合起来。下面的图很形象的说明了。)


------------------------------------------以上内容整理于《TCP/IP协议详解:卷1》--------------------------------------

------------------------------------------以下内容产生于代码及分析--------------------------------------

3. UDP宏定义实现

 C++ Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


// ******* UDP *******
#define UDP_HEADER_LEN   8
//源端口位置
#define UDP_SRC_PORT_H_P 0x22
#define UDP_SRC_PORT_L_P 0x23
//目标端口位置
#define UDP_DST_PORT_H_P 0x24
#define UDP_DST_PORT_L_P 0x25
//UDP数据长度位置
#define UDP_LEN_H_P          0x26
#define UDP_LEN_L_P          0x27
//UDP校验和位置
#define UDP_CHECKSUM_H_P 0x28
#define UDP_CHECKSUM_L_P 0x29
//UDP数据起始地址
#define UDP_DATA_P 0x2a

4. UDP函数实现

本TCP/IP协议栈中的UDP实现只一个 make_udp_reply_from_request函数——udp服务器,可以响应其他udp的请求。在连接的顺序看来,在stm32板子上面的为服务器,等待pc机客户端的请求,当请求到来的时候,返回由程序员自行设定的响应,如本文中将做出3个响应的例子( 当然udp一旦建立之后,就部分客户端和服务器端,地位是对等的,但是认为发起者为clien比较符合认知而已)。


这里说以下输入吧:buf为缓冲区,data为要传输的数据,datalen即为sizeof(data),port即为pc端的udp端口号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39


void make_udp_reply_from_request( unsigned  char *buf,  char *data,  unsigned  int datalen,  unsigned   int port)
{
     unsigned  int i =  0, tol_len;
     unsigned   int ck;
     //如前面的ARPICMP一样的
    make_eth(buf);
     // total length field in the IP header must be set:
     //如IP Header
    tol_len = IP_HEADER_LEN + UDP_HEADER_LEN + datalen;
    buf[IP_TOTLEN_H_P] = tol_len >>  8;
    buf[IP_TOTLEN_L_P] = tol_len;
     //如ICMP
    make_ip(buf);
     //本地UDP的端口号
    buf[UDP_DST_PORT_H_P] = port >>  8;
    buf[UDP_DST_PORT_L_P] = port & 0xff;
     // source port does not matter and is what the sender used.
     // calculte the udp length:最大16bit长度,即65535-14-20-8,但一般会设置的较小,原因么,上文里面讲过。
    buf[UDP_LEN_H_P] = datalen >>  8;
    buf[UDP_LEN_L_P] = UDP_HEADER_LEN + datalen;
     // zero the checksum
    buf[UDP_CHECKSUM_H_P] =  0;
    buf[UDP_CHECKSUM_L_P] =  0;

     // copy the data:
     while(i < datalen)
    {
        buf[UDP_DATA_P + i] = data[i];
        i++;
    }

     //UDP_DEBUG插入此处
     //这里的16字节是UDP的伪首部,即IP的源地址-0x1a+目标地址-0x1e(和标准的有差异),
     //+UDP首部=4+4+8=16
    ck = checksum(&buf[IP_SRC_P],  16 + datalen,  1);
    buf[UDP_CHECKSUM_H_P] = ck >>  8;
    buf[UDP_CHECKSUM_L_P] = ck & 0xff;
    enc28j60PacketSend(UDP_HEADER_LEN + IP_HEADER_LEN + ETH_HEADER_LEN + datalen, buf);
}

5. UDP实验

在有了以上的UDP实现之后,你还需要有UDP的请求进来,如下代码所示:


下面的代码放在一个while(1)或者RTOS进程里面,作为服务器来等待客户端的响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


/*--------------------- udp server start, we listen on udp port 1200=0x4B0 -----------------------------*/
       if (buf[IP_PROTO_P]==IP_PROTO_UDP_V&&buf[UDP_DST_PORT_H_P]== 4&&buf[UDP_DST_PORT_L_P]==0xb0)
      {
         //UDP数据长度
          udpdatalen=buf[UDP_LEN_H_P];
          udpdatalen=udpdatalen<< 8;
          udpdatalen=(udpdatalen+buf[UDP_LEN_L_P])-UDP_HEADER_LEN;
           //udpdatalen=buf[UDP_LEN_L_P]-UDP_HEADER_LEN;
            //获取pc端的udp port

          pcudpport=buf[UDP_SRC_PORT_H_P]<< 8 | buf[UDP_SRC_PORT_L_P];

         //将udp客户端得到的数据buf写入buf1,因为下面的实验需要输入的信息来做出相应的动作
           for(i1= 0; i1                        buf1[i1]=buf[UDP_DATA_P+i1];
                
          make_udp_reply_from_request(buf,buf1,udpdatalen, pcudpport);          
      }
/*----------------------------------------udp end -----------------------------------------------*/

ps:本实验中板子udp的port为1200,pc机的port为4001


实验部分实现了三个简单的实验:

通过串口输出UDP客户端的IP地址及端口号

通过串口和UDP输出UDP的输入数据,即USART ECHO和UDP ECHO

实现UDP命令控制STM32板子上面的LED


C++ Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90


void make_udp_reply_from_request( unsigned  char *buf,  char *data,  unsigned  int datalen,  unsigned   int port)
{
     unsigned  int i =  0, tol_len;
     unsigned   int ck;
     //如前面的ARP和ICMP一样的
    make_eth(buf);
     // total length field in the IP header must be set:
     //如IP Header
    tol_len = IP_HEADER_LEN + UDP_HEADER_LEN + datalen;
    buf[IP_TOTLEN_H_P] = tol_len >>  8;
    buf[IP_TOTLEN_L_P] = tol_len;
     //如ICMP
    make_ip(buf);
     //本地UDP的端口号
    buf[UDP_DST_PORT_H_P] = port >>  8;
    buf[UDP_DST_PORT_L_P] = port & 0xff;
     // source port does not matter and is what the sender used.
     // calculte the udp length:最大16bit长度,即65535-14-20-8,但一般会设置的较小,原因么,上文里面讲过。
    buf[UDP_LEN_H_P] = datalen >>  8;
    buf[UDP_LEN_L_P] = UDP_HEADER_LEN + datalen;
     // zero the checksum
    buf[UDP_CHECKSUM_H_P] =  0;
    buf[UDP_CHECKSUM_L_P] =  0;

     // copy the data:
     while(i < datalen)
    {
        buf[UDP_DATA_P + i] = data[i];
        i++;
    }

#ifdef UDP_DEBUG
    i =  0;
    printf( "UDP Server Test. rn");
    printf( "udp客户端的IP地址及端口号 : rn");

     while(i <  sizeof(ipv4_addr))
    {
         //注意这里我们建立的是UDP Server,输出UDP Client的IP地址
        printf( "%d", buf[IP_DST_P + i]);

         if(i !=  sizeof(ipv4_addr) -  1)
        {
            printf( ".");
        }

        i++;
    }

    i =  0;

[1] [2]
关键字:TCP  IP协议栈  UDP  STM32平台 引用地址:分析TCP/IP协议栈代码之UDP(STM32平台)

上一篇:STM32片上Flash内存映射、页面大小、寄存器映射
下一篇:STM32系列单片机命名规则

推荐阅读最新更新时间:2024-10-29 05:45

8位机嵌入式TCP通信速度的研究
0 引 言 长久以来,串行RS 232和RS 485通信技术一直是自动化仪器、仪表中常用的通信标准。但近年来,随着计算机技术、网络技术、通信技术的发展及其在工业自动化系统中的应用,使得工业自动化系统和仪器、仪表领域加速了向智能化、数字化和网络化方向发展的进程。出现了电力线通信技术、无线红外和蓝牙通信技术、基于USB接口的通信技术、现场总线技术以及嵌入式Internet接入技术等新技术。其中基于嵌入式Internet接入技术的网络化仪器是近年提出的全新概念,它是仪器检测技术与现代计算机技术、网络通信技术、微电子技术深度融合的产物口。检测仪器接入Internet,成为执行测量和控制任务的仪器Web站点,这种网络化仪器可以像普通仪器那
[嵌入式]
STM32移植lwip之建立tcp客户端
本篇目标:在之前能ping通pc机的工程基础上搭建tcp客户端,并可以主动发数据给pc机,同时也能与pc机收发数据,并在网络调试工具上显示 材料准备: 基础工程:修改后能ping通pc机的工程(STM32官方移植lwip修改代码) 调试工具:用来调试tcp连接下的数据接收(网络调试助手) 搭建工程:最终搭建好tcp客户端数据接收的工程(tcp客户端建立工程) 搭建TCP客户端 搭建TCP客户端的过程与上一章TCP服务器也相似,所以尽量把重点的地方加粗显示来区别 在搭建TCP客户端之前可以先理一下概念,客户端与服务器的区别: 客户端:主动建立tcp去连接目标IP 服务器:拥有静态IP,能让其他设备被动连接 因此用STM
[单片机]
<font color='red'>STM32</font>移植lwip之建立<font color='red'>tcp</font>客户端
西门子基于TCP/IP 的PLC通信技术分析
#1 IT&OT 深度融合 IT & OT integration 当今不断发展的工业自动化世界,在智能、高效和快速的系统和软件应用中,数据扮演着越来越重要的角色。传统的 IT 网络中,提供了丰富多彩的规范和协议,这些都可以帮助用户对数据进行充分地发掘。 而随着工业 4.0 的来临,IT、OT 的融合是大势所趋,IT 和 OT 之间的界限也越来越模糊,越来越多的 IT 技术被引入到 OT 应用之中,OT 处理自动化设备和现实的物理世界;而 IT 则更强调软件、数据和信息等,以前我们谈论PLC 通讯会想到自动化领域中的 PROFINET、S7、Modbus TCP 这些传统的工业通讯协议,而现在随着技术发展,SIMATIC PLC
[嵌入式]
西门子基于<font color='red'>TCP</font>/<font color='red'>IP</font> 的PLC通信技术分析
Modbus-RTU和Modbus-TCP如何进行协议解析和转换
Modbus协议是一种已广泛应用于当今工业控制领域的通用通讯协议,按其格式可分为Modbus-RTU,Modbus-ASCII,Modbus-TCP,其中前两者适用于串行通信控制网络中,例如RS485,RS232等,而Modbus-TCP主要应用于基于以太网TCP/IP通信的控制网络中。通过此协议,控制器相互之间、或控制器经由网络(如以太网)可以和其它设备之间进行通信。 许多工厂需要将现场各种不同型号设备的数据都能够通过一个上位机软件或者设备触摸屏整合起来监控管理,目前上位机大部分用的Modbus TCP协议,而现场设备有大批量使用的是Modbus RTU协议,要实现Modbus TCP访问Modbus RTU设备的需求日益增
[嵌入式]
Modbus-RTU和Modbus-<font color='red'>TCP</font>如何进行协议解析和转换
兼容TCP/IP协议的生物识别门禁系统研究
一、引 言 门禁系统【1】,又称为出入口控制系统,是安防领域的基础平台。随着计算机技术和网络技术的迅猛发展,门禁控制系统不断朝着集成化、智能化、网络化等方向发展。由于Internet网和以太网在全世界范围的广泛应用,网络化门禁控制系统已经成为门禁系统的重要发展方向,而TCP/IP协议以其独特的技术特点成为了网络化门禁系统的首选【2】。利用TCP/IP协议的网络通信门禁系统通过组建一个小型的局域网,很容易实现数据的远程传输和门禁各节点间的数据交互更新。 本文是利用TCP/IP协议的生物识别门禁系统的研究,利用网络接口芯片的工作原理实现网络通讯,对持卡人信息进行及时更新且上传给上位机进行监测,以判断是否允许进入,最终实现防止刷
[嵌入式]
W5100在嵌入式系统中TCP/IP网络通信的应用
   引言   我们原来介绍过W3150A网络芯片,由于W3150A使用时还必需要在外面接一个以太网物理层接口器件(RTL8201CP),增加了使用时的硬件难度,因此Wiznet公司最新推出了W5100,将TCP/IP协议栈、以太网的MAC和PHY三种功能集为一体。W5100不仅保留了原来与MCU接口的并行总线接口,还增加了SPI串行总线接口。   W5100器件的推出,大大简化了硬件电路设计,使单片机系统在没有操作系统的支持下,真正实现了单芯片接入Internet的理想。    芯片介绍   W5100有如下特性: 与MCU多种接口选择,直接总线接口、间接总线接口和SPI总线; 支持硬件TCP/IP
[嵌入式]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved