上一篇我们讲了esp8266连接路由器,这一篇就讲一下局域网中的UDP通信。
1、UDP简介
UDP 是User Datagram Protocol的简称。
翻译成中文是用户数据包协议,是OSI(Open System Interconnection开放式系统互联) 中一种无连接的传输层协议。
提供简单不可靠信息传送服务( 会丢数据包)
UDP协议位于传输层,是IP协议的上一层。UDP具有不提供数据包分组和不能对数据包进行排序的缺点。也就是当报文发送之后,是无法得知其是否安全完整到达的。
不过UDP协议也有他的优点,在许多应用中只支持UDP,如:多媒体数据流,因为不产生任何额外的数据,即使有破坏的包也不进行重发。
当强调传输性能而不是传输的完整性时,UDP是最好的选择。
2、esp8266进行UDP传输的几个结构体
下面我们讲一下怎么使用esp8266进行UDP传输数据。
主要用到下面的这个结构体struct espconn,如下
/** A espconn descriptor */
struct espconn {
/** type of the espconn (TCP, UDP) */
enum espconn_type type;
/** current state of the espconn */
enum espconn_state state;
union {
esp_tcp *tcp;
esp_udp *udp;
} proto;
/** A callback function that is informed about events
for this espconn */
espconn_recv_callback recv_callback;
espconn_sent_callback sent_callback;
uint8 link_cnt;
void *reverse;
};
type设置成UDP
proto使用联合体中的esp_udp *udp
recv_callback为接收回调函数
sent_callback发送数据回调函数
这个结构体好像没有设置目标IP和端口,那到底往哪发呢?
那这就需要下面这个结构体了,
这个就是上面proto指针指向的结构体esp_udp。
typedef struct _esp_udp {
int remote_port;
int local_port;
uint8 local_ip[4];
uint8 remote_ip[4];
} esp_udp;
remote_port为远程端口
local_port为本地端口
local_ip为本地IP(即8266自己的IP)
remote_ip为远程IP(发送到目标服务器的 IP)
3、实现UDP通信函数
有了上面的两个结构体,我们就可以写UDP通信的程序了,代码如下
void ICACHE_FLASH_ATTR UDP_conn_init() {
wifi_set_broadcast_if (STATIONAP_MODE);
user_udp_espconn.type = ESPCONN_UDP;
||分配内存给proto.udp指针
user_udp_espconn.proto.udp = (esp_udp*) os_zalloc(sizeof(esp_udp));
user_udp_espconn.proto.udp->local_port = 2525;
user_udp_espconn.proto.udp->remote_port = 1112;
||用于存放远程IP地址
const char udp_remote_ip[4] = { 192, 168, 0, 104 };
os_memcpy(&user_udp_espconn.proto.udp->remote_ip, udp_remote_ip, 4);
||接收回调函数
espconn_regist_recvcb(&user_udp_espconn, user_udp_recv_cb);
||发送回调函数
espconn_regist_sentcb(&user_udp_espconn, user_udp_sent_cb);
||创建UDP连接
espconn_create(&user_udp_espconn);
||发送数据
user_udp_send();
}
此函数在路由器连接成功之后调用。
避坑指南:
注意第一条语句,
wifi_set_broadcast_if (STATIONAP_MODE);
必须的加上,否则会接收不到数据,
为什么会接收不到数据呢?
编程指南上有讲,大家可以看下,我也把他贴到下面了,如图:
UDP广播包居然默认是从soft-AP发送,而且仅从station发还会影响soft-AP功能,所以我们直接设置成3 station和soft-AP均发送(STATIONAP_MODE)
两个回调函数和发送函数也贴到下面
os_timer_t test_timer;
||UDP发送函数
void ICACHE_FLASH_ATTR user_udp_send(void){
char yladdr[6];
||将获取的MAC地址格式化输出到一个buffer里面
char Buffer[40]={0};
||获取MAC地址
wifi_get_macaddr(STATION_IF,yladdr);
||格式化MAC地址
os_sprintf(Buffer,"ESP8266的MAC地址为"MACSTR"!!!\r\n",
MAC2STR(yladdr));
espconn_sent(&user_udp_espconn,Buffer,os_strlen(Buffer));
}
||发送回调函数
void ICACHE_FLASH_ATTR user_udp_sent_cb(void *arg){
||定时发送
os_timer_disarm(&test_timer);
os_timer_setfn(&test_timer,user_udp_send,NULL);
os_timer_arm(&test_timer,1000,NULL);//定1秒钟发送一次
}
||接收回调函数
void ICACHE_FLASH_ATTR user_udp_recv_cb(void *arg,
char *pdata,unsigned short len){
char temp[128];
os_sprintf(temp,"UDP recive:%s",pdata);
||UDP接收到的数据打印出来
os_printf("%s",temp);
}
编译、下载程序,执行如下图;
注意两个端口要和程序中的对应,电脑的本地端口就是8266的远端端口。
好了,UDP实验就算成功了,
可是好像还是有点疑问,
UDP协议不是一种无连接的传输层协议吗?
那为啥在局域网内还要指定IP呢?
其实,也可以不指定IP,
只要把8266的远端ip设置成255.255.255.255就可以了,
这样局域网内的服务器就都可以收到数据了(注意端口要一致)
你也可以试试。
(* ̄︶ ̄)
原创不易,如果你喜欢我的公众号、觉得我 文章对你有所启发,
请务必“点赞、收藏、转发”,这对我很重要,谢谢!
欢迎订阅 嵌入式小书虫