本篇文章主要是对微信小程序连接小熊派的通信过程进行记录与整合。下面将以点亮开发板的灯为案例来讲,如果浏览量可以的话,我会尝试出正式开发环境下微信小程序与华为开发板通信的案例,请点赞或评论。
开发环境
【开发板】:BearPi-HM_Nano
【芯片手册】:Hi3861V100
【微信小程序版本】:稳定版 Stable Build (1.05.2201240 | 1.06.2201240)
开发板UDP接口
在socket.h
中包含声明UDP协议相关接口函数。
接口名 | 功能描述 |
---|---|
socket | 创建套接字 |
bind | 将ip和端口绑定到嵌套字 |
sendto | 将数据由指定的socket发送给对方主机 |
recvfrom | 从指定主机接收UDP数据 |
close | 关闭套接字 |
开启和连接UDP服务器的条件:
- 需要连接WiFi
- 客户端与服务器需要在同一局域网
UDP服务器创建流程
下面将会按照顺序讲解UDP服务器整体创建过程
- 连接WiFi
通过连接WiFi可以知道UDP服务器的IP地址,后续微信小程序通过这个IP地址发送消息。WifiConnect(WIFI_ACCOUNT, WIFI_PASSWD);
- 创建Socket
网络通信需要创建socket,这样两个端才能通过套接字发送和接收数据。// 0 AF_UNSPEC: 适用于指定主机名和服务名且适合任何协议族的地址 // 2 AF_INET: Ipv4 // 10 AF_INET6: Ipv6 // 1 SOCK_STREAM: TCP协议 网络层 // 2 SOCK_DGRAM: UDP协议 网络层 // 3 SOCK_RAW: 套接字 网络层 int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
- 设置UDP服务器和UDP客户端
通过设置INADDR_ANY
参数接收任何主机发送过来的数据,并且指定服务器使用哪个端口。// htonl函数将32位数主机字节顺序转换成网络字节顺序 // INADDR_ANY 0.0.0.0 ((in_addr_t) 0x00000000) struct sockaddr_in server_sock; // 服务器 server_sock.sin_family = AF_INET; // 地址族 server_sock.sin_addr.s_addr = htonl(INADDR_ANY); // IP地址 server_sock.sin_port = htons(8888); // 端口号 struct sockaddr_in client_sock; // 客户端
- Socket与UDP服务器进行绑定
bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)
上面的步骤完成后,可以通过sendto()
与recvfrom()
发送和接收数据。
开启UDP服务器完整代码(不含LED部分)
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "lwip/sockets.h"
#include "wifi_connect.h"
#define WIFI_ACCOUNT "请填写WiFi的SSID"
#define WIFI_PASSWD "请填写WiFi的密码"
#define _PROT_ "请填写服务器的端口号"
int sock_fd, new_sock_fd;
char recvBuff[512];
char *buff = "I'm UDP Server.\r\n";
static void UDPServerTask(void)
{
printf("Into UDPServerTask!\r\n");
// 服务器地址信息
struct sockaddr_in server_sock;
server_sock.sin_family = AF_INET;
server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
server_sock.sin_port = htons(_PROT_);
// 客户端地址信息
struct sockaddr_in client_sock;
socklen_t sin_size;
// 连接WiFi
printf("Into WiFi!\r\n");
WifiConnect(WIFI_ACCOUNT, WIFI_PASSWD);
// 创建socket
printf("Create Socket\r\n");
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("Socket Is Error.\r\n");
exit(1);
}
// 清理数据
printf("Clean Data.\r\n");
bzero(&server_sock, sizeof(server_sock));
// 调用 Bind 绑定Socket和UAP服务器
printf("Bind Socket and Adrr.\r\n");
if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
{
perror("Bind Is Error.\r\n");
exit(1);
}
ssize_t ret;
while (1)
{
sin_size = sizeof(struct sockaddr_in);
while (1)
{
// 清理缓存数据
printf("Clean Data.\r\n");
bzero(recvBuff, sizeof(recvBuff));
// 接收数据
if ((ret = recvfrom(sock_fd, recvBuff, sizeof(recvBuff), 0, (struct sockaddr *)&client_sock, (socklen_t *)&sin_size)) == -1)
{
printf("Recv Error.\r\n");
}
// 发送数据
if ((ret = sendto(new_sock_fd, buff, strlen(buff) + 1, 0, (struct sockaddr *)&client_sock, sizeof(client_sock))) == -1)
{
printf("Send : \r\n");
}
}
// 关闭UAP服务器
printf("Close Server.\r\n");
close(new_sock_fd);
}
}
/* UDP 服务的入口函数 */
static void UDPServerEntry(void)
{
osThreadAttr_t threadAttr;
threadAttr.attr_bits = 0U;
threadAttr.cb_mem = NULL;
threadAttr.cb_size = 0U;
threadAttr.stack_mem = NULL;
threadAttr.stack_size = 10240;
threadAttr.priority = 24;
threadAttr.name = "UDPServerTask";
if (osThreadNew((osThreadFunc_t)UDPServerTask, NULL, &threadAttr) == NULL){
printf("Falied To Create UDPServerTask.\r\n");
}
}
APP_FEATURE_INIT(UDPServerEntry);
相关函数说明
/* 用来将上一个函数发生错误的原因输出到标准设备(stderr) */
void perror(const char *);
/* 置字节字符串前size个字节为零且包括‘\0’ */
int bzero((void *)(target), (size_t)(size));
/* 在许多操作系统命令行壳层和脚本语言中含有的命令,此命令导致shell或程序终止 */
int exit(1);
/* UDP服务器断开 */
int close(int);
微信UDP客户端创建流程
创建UDP客户端基本流程:
- 创建UDP客户端
this.udp = wx.createUDPSocket();
- 绑定端口号
可以不指定port
,将会随机绑定一个本机可用端口号this.udp.bind(number port);
- 设置接收函数
callback
为处理接收到消息的函数this.udp.onMessage(function callback);
- 向UDP服务器发送消息
this.udp.send(Object object);
UDP客户端完整代码(不含LED部分)
<!--index.wxml-->
<view class="container">
<button bindtap="send">向UDP服务发送消息</button>
</view>
<view class="res_container">
{{udpResData}}
</view>
// index.js
const app = getApp()
let Utf8ArrayToStr = require('./Utf8ArrayToStr.js');
Page({
data: {
udpResData: ''
},
// 点击处理事件
send: function(e) {
// 向指定的 IP 和 port 发送消息
this.udp.send({
address: '172.17.3.8',
port: '3641',
message: 'hello, how are you'
})
},
// UDP 接收到数据的事件处理函数,参数res={message,remoteInfo}
onUdpMessage: function(res) {
console.log(res);
if(res.remoteInfo.size > 0) {
console.log('onUdpMessage() 接收数据 ' + res.remoteInfo.size + ' 字节:' + JSON.stringify(res, null, '\t'));
// 接收onMessage 收到的message是ArrayBuffer缓冲,不能直接输出,要另转String处理
// 此工具类可以解决 uint8Array转String 中文乱码的问题
let messageStr = Utf8ArrayToStr.Utf8ArrayToStr(new Uint8Array(res.message))
// 更新接收内容
this.setData({
udpResData: 'udp接收到的内容: ' + messageStr
})
}
},
// 页面加载完成事件由系统调用
onLoad: function () {
// 新建udp实例
this.udp = wx.createUDPSocket()
// udp绑定本机
this.udp.bind()
// 指定接收事件处理函数,监听收到消息的事件
this.udp.onMessage(this.onUdpMessage)
console.log('页面 index 加载完成事件onLoad()')
},
})
// Utf8ArrayToStr.js
function Utf8ArrayToStr(array) {
var out, i, len, c;
var char2, char3;
out = "";
len = array.length;
i = 0;
while (i < len) {
c = array[i++];
switch (c >> 4) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
out += String.fromCharCode(c);
break;
case 12: case 13:
char2 = array[i++];
out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
break;
case 14:
char2 = array[i++];
char3 = array[i++];
out += String.fromCharCode(((c & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0));
break;
}
}
return out;
}
module.exports = {
Utf8ArrayToStr: Utf8ArrayToStr
}
效果图
首先你需要知道udp服务是个不稳定的,他不能保证能连接到服务器。所以需要多次发送数据,板子才能接收到。
相应UI界面代码下载链接:https://download.csdn.net/download/hjh_cos/83066593
如果你是无意刷到这篇文章并看到这里,希望你给我的文章来一个赞赞👍👍。如果你不同意其中的内容或有什么问题都可以在下方评论区留下你的想法或疑惑,谢谢你的支持!!😀😀