HarmonyOS 网络应用开发 原创
@toc
1.UDP客户端
1.1 UDP协议相关API介绍
socket.h接口简介:
这个socket.h中包含声明UDP协议相关接口函数。
接口名 | 功能描述 |
---|---|
socket | 创建套接字 |
sendto | 将数据由指定的socket发送到远端主机 |
recvfrom | 从远端主机接收UDP数据 |
close | 关闭套接字 |
1.2 UDP客户端创建流程介绍
1.3 实现UDP客户端
打开“D3_iot_udp_client”工程的udp_client_demo.c文件,可在代码中查看实现UDP客户端的代码
static void UDPClientTask(void)
{
//服务器的地址信息
struct sockaddr_in send_addr;
socklen_t addr_length = sizeof(send_addr);
char recvBuf[512];
//连接Wifi
WifiConnect("TP-LINK_65A8", "0987654321");
//创建socket
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("create socket failed!\r\n");
exit(1);
}
//初始化预连接的服务端地址
send_addr.sin_family = AF_INET;
send_addr.sin_port = htons(_PROT_);
send_addr.sin_addr.s_addr = inet_addr("192.168.0.175");
addr_length = sizeof(send_addr);
//总计发送 count 次数据
while (1)
{
bzero(recvBuf, sizeof(recvBuf));
//发送数据到服务远端
sendto(sock_fd, send_data, strlen(send_data), 0, (struct sockaddr *)&send_addr, addr_length);
//线程休眠一段时间
sleep(10);
//接收服务端返回的字符串
recvfrom(sock_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr *)&send_addr, &addr_length);
printf("%s:%d=>%s\n", inet_ntoa(send_addr.sin_addr), ntohs(send_addr.sin_port), recvBuf);
}
//关闭这个 socket
closesocket(sock_fd);
}
ip地址要改为电脑的ip地址
代码讲解过程见:
https://www.bilibili.com/video/BV1tv411b7SA?p=10&share_source=copy_web&vd_source=8f1cf1d7278a65d1271a6ccbd8891dc6 P25
2.TCP服务端
2.1 TCP协议相关API介绍
socket.h接口简介:
这个socket.h中包含声明TCP协议相关接口函数。
接口名 | 功能描述 |
---|---|
socket | 创建套接字 |
bind | 为套接字关联了一个相应的地址与端口号 |
listen | 将套接字设置为监听模式 |
accept | 接受套接字上新的连接 |
recv | 接收数据 |
send | 发送数据 |
close | 关闭套接字 |
2.2 TCP服务端创建流程介绍
2.3 实现TCP服务端
打开“D4_iot_tcp_server”工程的tcp_server_demo.c文件,可以查看实现TCP服务的代码。
//创建socket
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket is error\r\n");
exit(1);
}
bzero(&server_sock, sizeof(server_sock));
server_sock.sin_family = AF_INET;
server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
server_sock.sin_port = htons(_PROT_);
//调用bind函数绑定socket和地址
if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
{
perror("bind is error\r\n");
exit(1);
}
//调用listen函数监听(指定port监听)
if (listen(sock_fd, TCP_BACKLOG) == -1)
{
perror("listen is error\r\n");
exit(1);
}
printf("start accept\n");
代码讲解过程见:
https://www.bilibili.com/video/BV1tv411b7SA?p=10&share_source=copy_web&vd_source=8f1cf1d7278a65d1271a6ccbd8891dc6 P26
3.TCP客户端
3.1 TCP协议相关API介绍
socket.h接口简介:
这个socket.h中包含声明TCP协议相关接口函数。
接口名 | 功能描述 |
---|---|
socket | 创建套接字 |
connect | 连接到指定的主机 |
send | 发送数据 |
recv | 接收数据 |
close | 关闭套接字 |
3.2 TCP客户端创建流程介绍
3.3 实现TCP客户端
打开“D3_iot_udp_client”工程的udp_client_demo.c文件,修改部分代码即可实现TCP客户端。
原代码:
static void UDPClientTask(void)
{
//服务器的地址信息
struct sockaddr_in send_addr;
socklen_t addr_length = sizeof(send_addr);
char recvBuf[512];
//连接Wifi
WifiConnect("TP-LINK_65A8", "0987654321");
//创建socket
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("create socket failed!\r\n");
exit(1);
}
//初始化预连接的服务端地址
send_addr.sin_family = AF_INET;
send_addr.sin_port = htons(_PROT_);
send_addr.sin_addr.s_addr = inet_addr("192.168.0.175");
addr_length = sizeof(send_addr);
//总计发送 count 次数据
while (1)
{
bzero(recvBuf, sizeof(recvBuf));
//发送数据到服务远端
sendto(sock_fd, send_data, strlen(send_data), 0, (struct sockaddr *)&send_addr, addr_length);
//线程休眠一段时间
sleep(10);
//接收服务端返回的字符串
recvfrom(sock_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr *)&send_addr, &addr_length);
printf("%s:%d=>%s\n", inet_ntoa(send_addr.sin_addr), ntohs(send_addr.sin_port), recvBuf);
}
//关闭这个 socket
closesocket(sock_fd);
}
修改后代码:
static const char *send_data = "Hello! I'm BearPi-HM_Nano TCP Client!\r\n";
static void TCPClientTask(void)
{
//服务器的地址信息
struct sockaddr_in send_addr;
socklen_t addr_length = sizeof(send_addr);
char recvBuf[512];
//连接Wifi
WifiConnect("TP-LINK_65A8", "0987654321");
//创建socket
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("create socket failed!\r\n");
exit(1);
}
//初始化预连接的服务端地址
send_addr.sin_family = AF_INET;
send_addr.sin_port = htons(_PROT_);
send_addr.sin_addr.s_addr = inet_addr("192.168.0.175");
addr_length = sizeof(send_addr);
connect(sock_fd,(struct sockaddr *)&send_addr,addr_length)
//总计发送 count 次数据
while (1)
{
bzero(recvBuf, sizeof(recvBuf));
//发送数据到服务远端
send(sock_fd, send_data, strlen(send_data), 0);
//线程休眠一段时间
sleep(10);
//接收服务端返回的字符串
recv(sock_fd, recvBuf, sizeof(recvBuf), 0);
printf("%s:%d=>%s\n", inet_ntoa(send_addr.sin_addr), ntohs(send_addr.sin_port), recvBuf);
}
//关闭这个 socket
closesocket(sock_fd);
}
static void TCPClientDemo(void)
{
osThreadAttr_t attr;
attr.name = "TCPClientTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 10240;
attr.priority = osPriorityNormal;
if (osThreadNew((osThreadFunc_t)TCPClientTask, NULL, &attr) == NULL)
{
printf("[TCPClientDemo] Falied to create TCPClientTask!\n");
}
}
APP_FEATURE_INIT(TCPClientDemo);
代码讲解过程见:
https://www.bilibili.com/video/BV1tv411b7SA?p=10&share_source=copy_web&vd_source=8f1cf1d7278a65d1271a6ccbd8891dc6 P27
4. UDP服务端
4.1 UDP协议相关API介绍
socket.h接口简介:
这个socket.h中包含声明UDP协议相关接口函数。
接口名 | 功能描述 |
---|---|
socket | 创建套接字 |
bind | 将ip和端口绑定到嵌套字 |
sendto | 将数据由指定的socket发送对方主机 |
recvfrom | 从指定主机接收UDP数据 |
close | 关闭套接字 |
4.2 UDP服务端创建流程介绍
4.3 实现UDP服务端
打开“D4_iot_tcp_server”工程的tcp_server_demo.c文件,修改部分代码即可实现UDP服务端。
原代码:
static void TCPServerTask(void)
{
//服务端地址信息
struct sockaddr_in server_sock;
//客户端地址信息
struct sockaddr_in client_sock;
int sin_size;
struct sockaddr_in *cli_addr;
//连接Wifi
WifiConnect("TP-LINK_65A8", "0987654321");
//创建socket
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket is error\r\n");
exit(1);
}
bzero(&server_sock, sizeof(server_sock));
server_sock.sin_family = AF_INET;
server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
server_sock.sin_port = htons(_PROT_);
//调用bind函数绑定socket和地址
if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
{
perror("bind is error\r\n");
exit(1);
}
//调用listen函数监听(指定port监听)
if (listen(sock_fd, TCP_BACKLOG) == -1)
{
perror("listen is error\r\n");
exit(1);
}
printf("start accept\n");
//调用accept函数从队列中
while (1)
{
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sock_fd, (struct sockaddr *)&client_sock, (socklen_t *)&sin_size)) == -1)
{
perror("accept");
continue;
}
cli_addr = malloc(sizeof(struct sockaddr));
printf("accept addr\r\n");
if (cli_addr != NULL)
{
memcpy(cli_addr, &client_sock, sizeof(struct sockaddr));
}
//处理目标
ssize_t ret;
while (1)
{
if ((ret = recv(new_fd, recvbuf, sizeof(recvbuf), 0)) == -1)
{
printf("recv error \r\n");
}
printf("recv :%s\r\n", recvbuf);
sleep(2);
if ((ret = send(new_fd, buf, strlen(buf) + 1, 0)) == -1)
{
perror("send : ");
}
sleep(2);
}
close(new_fd);
}
}
修改后代码:
//在sock_fd 进行监听,在 new_fd 接收新的链接
int sock_fd, new_fd;
char recvbuf[512];
char *buf = "Hello! I'm BearPi-HM_Nano UDP Server!";
static void UDPServerTask(void)
{
//服务端地址信息
struct sockaddr_in server_sock;
//客户端地址信息
struct sockaddr_in client_sock;
int sin_size;
struct sockaddr_in *cli_addr;
//连接Wifi
WifiConnect("TP-LINK_65A8", "0987654321");
//创建socket
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("socket is error\r\n");
exit(1);
}
bzero(&server_sock, sizeof(server_sock));
server_sock.sin_family = AF_INET;
server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
server_sock.sin_port = htons(_PROT_);
//调用bind函数绑定socket和地址
if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
{
perror("bind is error\r\n");
exit(1);
}
//调用listen函数监听(指定port监听)
//if (listen(sock_fd, TCP_BACKLOG) == -1)
//{
// perror("listen is error\r\n");
// exit(1);
//}
//printf("start accept\n");
//调用accept函数从队列中
while (1)
{
sin_size = sizeof(struct sockaddr_in);
// if ((new_fd = accept(sock_fd, (struct sockaddr *)&client_sock, (socklen_t *)&sin_size)) == -1)
// {
// perror("accept");
// continue;
// }
// cli_addr = malloc(sizeof(struct sockaddr));
// printf("accept addr\r\n");
// if (cli_addr != NULL)
// {
// memcpy(cli_addr, &client_sock, sizeof(struct sockaddr));
// }
//处理目标
ssize_t ret;
while (1)
{
if ((ret = recvfrom(sock_fd, recvbuf, sizeof(recvbuf), 0,(struct sockaddr *)&client_sock, (socklen_t *)&sin_size)) == -1)
{
printf("recv error \r\n");
}
printf("recv :%s\r\n", recvbuf);
//sleep(2);
if ((ret = sendto(sock_fd, buf, strlen(buf) + 1, 0,(struct sockaddr *)&client_sock,sizeof(client_sock))) == -1)
{
perror("send : ");
}
//sleep(2);
}
close(new_fd);
}
}
static void UDPServerDemo(void)
{
osThreadAttr_t attr;
attr.name = "UDPServerTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 10240;
attr.priority = osPriorityNormal;
if (osThreadNew((osThreadFunc_t)UDPServerTask, NULL, &attr) == NULL)
{
printf("[UDPServerDemo] Falied to create UDPServerTask!\n");
}
}
APP_FEATURE_INIT(UDPServerDemo);
代码讲解过程见:
https://www.bilibili.com/video/BV1tv411b7SA?p=10&share_source=copy_web&vd_source=8f1cf1d7278a65d1271a6ccbd8891dc6 P28
5. MQTT客户端
5.1 MQTT介绍
MOTT (Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。
Paho是IBM在2011年建立的Eclipse开源项目,该项目包含以C、Java、Python、Javascript等语言编写的可用客户端。
嵌入式c语言客户端开源地址:
https://github.com/eclipse/paho.mqtt.embedded-c
5.2 Paho MQTT文件目录介绍
- MQTTClient:封装MQTTPacket生成的高级别C++客户端程序。
- MQTTClient-C:封装MQTTPacket生成的高级别C客户端程序
- samples目录提供FreeRTOS和linux两个例程,分别支持FreeRTOS和Linux系统。
- src目录提供MQTTClient的代码实现能力,以及用于移植到对应平台的网络驱动
- MQTTPacket:提供MQTT数据包的序列化与反序列化,以及部分辅助函数。
5.3 如何使用Paho MQTT
在MQTTClient.h中包含声明Paho MQTT相关接口函数。
接口名 | 功能描述 |
---|---|
MQTTClientlnit | 创建一个客户端对象 |
MQTTConnect | 发送MQTT连接数据包 |
MQTTConnectWithResults | 发送MQTT连接数据包并等待返回 |
MQTTPublish | 发送MQTT发布数据包 |
MQTTSetMessageHandler | 发送每个topic消息处理函数 |
MQTTSubscribe | 发送MQTT订阅数据包 |
MQTTSubscribeWithResults | 发送MQTT订阅数据包并等待返回结果 |
MQTTUnsubscribe | 发送MQTT取消数据包 |
MQTTDisconnect | 发送MQTT断开连接数据包并关闭连接 |
5.4 实现MQTT客户端
打开“D5_iot_mqtt”工程的iot_mqtt.c文件,查看实现MQTT客户端的代码。
NetworkConnect(&network, "192.168.0.176", 1883);
printf("MQTTClientInit ...\n");
MQTTClientInit(&client, &network, 2000, sendBuf, sizeof(sendBuf), readBuf, sizeof(readBuf));
MQTTString clientId = MQTTString_initializer;
clientId.cstring = "bearpi";
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
data.clientID = clientId;
data.willFlag = 0;
data.MQTTVersion = 3;
data.keepAliveInterval = 0;
data.cleansession = 1;
printf("MQTTConnect ...\n");
rc = MQTTConnect(&client, &data);
if (rc != 0) {
printf("MQTTConnect: %d\n", rc);
NetworkDisconnect(&network);
MQTTDisconnect(&client);
osDelay(200);
goto begin;
}
printf("MQTTSubscribe ...\n");
rc = MQTTSubscribe(&client, "substopic", 2, messageArrived);
if (rc != 0) {
printf("MQTTSubscribe: %d\n", rc);
osDelay(200);
goto begin;
}
while (++count)
{
MQTTMessage message;
char payload[30];
message.qos = 2;
message.retained = 0;
message.payload = payload;
sprintf(payload, "message number %d", count);
message.payloadlen = strlen(payload);
if ((rc = MQTTPublish(&client, "pubtopic", &message)) != 0){
printf("Return code from MQTT publish is %d\n", rc);
NetworkDisconnect(&network);
MQTTDisconnect(&client);
goto begin;
}
osDelay(50);
}
代码讲解过程见:
https://www.bilibili.com/video/BV1tv411b7SA?p=10&share_source=copy_web&vd_source=8f1cf1d7278a65d1271a6ccbd8891dc6 P29
本部分代码也做了一些更新,如果发现代码不一样的话,可以去gitee同步一下