ESP32多机通信,ESP32和Ubuntu通过UDP组建的简单C/S模型

一、简介

使用Ubuntu搭建UDP服务器,ESP32作为客户端。实现ESP32和ESP32之间的通信,以及ESP32和服务器直接的通信。

二、需要的工具

  1. ESP32 至少两片
  2. 一台Ubuntu主机

三、总体流程

在这里插入图片描述

四、服务器

为实现通信要求,服务器要求具有以下的功能。首先是实现UDP数据接受发送,这是通信的基础;其次是对来自ESP32的数据做出反应,主要包括两种,一种是返回ESP32某种数据,一种是对ESP32发来的数据进行某种处理。
服务器流程图

流程图详解

按照流程图所示:
第一步先是要初始化UDP通信,我设计的这个系统的整体通信都是基于UDP网络通信实现的;第二步建立一个空的用户列表,这个用户列表后期会被用来存储每一个ESP32的基本信息。最后,阻塞等待UDP数据,每收到一个数据就建立一个线程对这个数据进行处理。下面的介绍详细的描述了这个过程:

  1. UDP通信的socket编程,UDP是本设计系统的基本通信方式,系统中所有的数据接收和发送都是基于UDP通信实现。如果在云服务器下则需要考虑开放端口的问题,首先要配置服务器的防火墙,开放系统后期将要进行通信的端口;其次还要配置服务器的一系列安全策略的组件,并开放所有的通信端口。
  2. 用户列表的创建和维护,用户列表使用一个数组来存储数据,作为更好的解决方案应该使用数据库或者文件的形式保存用户列表,此处要考虑模型的验证则需要使用简单的数组来简化程序的编写难度。我们在系统中用的控制终端的列表数据的基本格式定义:
// 控制终端信息
typedef struct{
    	char id;
    	char ip[16];
    	short unsigned int port;
    	describe des;
}user_info;
user_info user_info_list[MAX_COUNT_OF_CLIENT];
  1. 等待UDP数据,监听UDP端口并等待数据。
  2. 对数据进行初步的校准验证,数据格式如下图4.3所示,初步校验其实就是判断第一个字节是不是0XFE。如果是就在下一步创建新的线程来处理接收到的数据,否则就返回上一步继续等待UDP数据。
    数据格式示意图
  3. 线程的创建和数据锁,如果系统检测收到一个数据就建立一个线程,在线程中处理接收到的数据。数据锁的主要功能是为用户提供列表服务,防止用户列表在线程间由于同时读写的问题产生错误。
  4. 判断当前接收到的数据的发送方是否是在用户列表中存在,如果存在就进入下一步去判断接收方;不存在则在用户列表中加入该用户,在控制终端列表中加入控制终端前需要获取数据锁,加入控制终端的任务完成之后要释放该数据锁。
  5. 判断接收方是服务器还是控制终端,如果是发送给其他控制终端的则服务器起到数据中转和记录的作用;在数据中转之前要先判断接收方是否正确,即遍历控制终端列表中是否存在该终端机,存在则转发数据,转发完成结束线程;如果不存在记录错误就结束此线程。
    在这里插入图片描述
    判断接收方是服务器还是控制终端(图4.4)
  6. 接收方式服务器则根据不同的数据进行处理。

UPD通信控制数据格式

在这里插入图片描述
如图所示,基本所有在网络间传输的数据都要遵循上图所示的规则。每次进行通信的数据都是由若干个字节构成的(最少 3 个字节)。
第一个字节用于初步校验,即在服务器刚收到数据时就通过该字节是不是程序需要的数据,是需求的数据才将进入下一步,不是则直接丢弃该数据。
第二个字节用来判断接收方,数据分为发送给服务器和转发给其他控制终端的数据。第二个字节如果是0 ,则表示该数据会交给服务器来进行处理;如果是非 0 则表示数据是要发送给其他控制终端来处理的,服务器在这一步里只起到了转发数据的功能。
以上两种情况对于不同的第三个字节以及第三个字节以后的数据,接收方为服务器时,第三字节为0、1、2、3分别代表更改自己的描述信息、给服务器发送的信息、获取控制终端机列表、控制终端主动断开。
更改自己的数据描述信息,从第四字节开始存储描述信息,描述信息的结构定义如下:

#define DESCRIBE_SIZE 32
// 描述信息
typedef struct{
      char type;
      char describe[DESCRIBE_SIZE];
}describe;

在给服务器发送信息时要保留数据的格式,数据格式并未给明确的定义。在服务器上,代码里会直接以字符串的形式对数据进行输出。
获取控制终端机列表,第三字节为2表示获取控制终端列表,这个通信过程只有三个字节。系统收到这个信号之后,服务器将开始以规定的数据格式向发起这个请求信号的控制终端回发一个控制终端的列表。这里所说的规定的数据格式在后面的章节中会有介绍。
控制终端会主动断开,第三字节为3的时候表示控制终端会主动断开此时的连接,这个通信过程也只有三个字节。收到这个信号之后服务器会首先获取数据锁,获取到之后从控制终端列表中删除这个控制终端,释放数据锁,然后结束此刻进行的线程。

五、ESP32流程图

在这里插入图片描述
首先对OLED进行初始化,我在本系统的设计中采用了0.9寸的OLED显示屏作为输出显示模块,一般0.9寸的OLED显示屏模块都支持SPI和IIC通信,ESP32作为一个IO比较少的单片机使用这两种通信方式都可以很大程度上节约IO资源。
开启Station模式,即初始化ESP32的Station工作模式,使ESP32作为一个路由的终端接入网络。需要注意的是在ESP32中初始化话Station工作模式之前需要初始化NVS存储系统,因为关于网络的硬件信息需要从NVS分区读取。
UDP的连接使用中,在使能Station模式之后就要开始创建UDP连接使得该设备可以连接到服务器,创建UDP连接可以使用类似Linux的socket网络编程,也可以使用esp-idf封装的UDP网络函数,这两种方法本质上没有差别,都可以实现我们设计中要求的网络连接,我在本设计中使用了第二种方法。在使用后者时,创建UDP连接的过程中需要注册接收回调函数,该函数在UDP接收到数据后会被调用。具体注册如下:

    // 注册接收回调函数
    udp_recv(my_udp_pcb, my_udp_recv, NULL);

my_udp_recv为注册的回调函数名,my_udp_pcb是关于UDP控制的数据结构体。
接收回调函数会在每一次UDP接收到数据之后被调用,在接收回调函数中处理接收到的数据,在本设计中的处理方式为通过OLED显示出相应的信息。
依次发送测试数据,分别是更改描述信息、给服务器发送信息、获取客户机列表、主动断开连接的测试信息

六、参考程序下载

这是我的毕业设计作品,上述的功能都是实现的,哦,除了数据锁的那个,最后赶作品没有加,不过我们毕业的时候的测试场景都是非常的简单,根本不可能出现数据冲突。没有下载币的同学可以私信我或者发邮件[email protected]

发布了8 篇原创文章 · 获赞 18 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_31232793/article/details/103158766