文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

学习设备开发之Hi3861-TCPclient-开关灯

2024-12-01 01:52

关注

想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

一、前言

学习OpenHarmony南向设备开发中的网络通信,它可以将底层开发板获得的数据传输到上层的服务器,服务器亦可通过网络通信控制底层开发板。

二、TCP简介

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 79 定义。
TCP旨在适应支持多网络应用的分层协议层次结构。 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务。TCP假设它可以从较低级别的协议获得简单的,可能不可靠的数据报服务。 原则上,TCP应该能够在从硬线连接到分组交换或电路交换网络的各种通信系统之上操作。

网络编程开发绕不开socket(套接字)的使用,socket就是整合好TCP/IP协议的一个工具。让我们无需过度关注于底层协议的实现,直接用封装好的socket就行了.

TCP服务器端与TCP客户端进行通信的流程👇

三、分析代码

本次实验使用的是OpenHarmony1.0.0的源码:​​源码压缩包地址​​参考HiSpark WiFi-IoT 鸿蒙套件样例开发–网络编程(tcpclient)

1.导入样例

将润和提供的21_tcpclient开发样例文件夹复制到源码applications/sample/wifi-iot/app路径下:


在app路径下的BUILD.gn添加需要编译的静态库名称:tcpclient:net_demo。

import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
features = [
"startup",
"tcpclient:net_demo",
]
}

静态库名称可在21_tcpclient文件夹下的BUILD.gn里查看。

踩坑:一开始直接写静态库名net_demo是会报错的!

报错内容👇一般都是BUILD.gn文件出现问题:

2、分析代码

事先在net_params.h文件里修改WiFi的配置。

程序入口:demo_entry_cmsis.c文件。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "iot_gpio.h"

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "net_demo.h"
#include "net_params.h"
#include "wifi_connecter.h"

#define LED_TASK_GPIO 9
static void NetDemoTask(void *arg) //一开始线程入口函数
{
(void)arg;
WifiDeviceConfig config = {0}; //表示用于连接到指定 Wi-Fi 设备的 Wi-Fi 站配置。
IoTGpioInit(LED_TASK_GPIO); //初始化IO口,为后文点灯做准备
IoTGpioSetDir(LED_TASK_GPIO, IOT_GPIO_DIR_OUT); //设置GPIO为输出模式
// 准备AP的配置参数
strcpy(config.ssid, PARAM_HOTSPOT_SSID); //从net_params.h拷贝WiFi的参数
strcpy(config.preSharedKey, PARAM_HOTSPOT_PSK);
config.securityType = PARAM_HOTSPOT_TYPE; //配置WiFi的安全模式
osDelay(10);
int netId = ConnectToHotspot(&config); //连接热点
int timeout = 10;
while (timeout--) //等待10秒后开始执行NetDemoTest
{
printf("After %d seconds, I will start %s test!\r\n", timeout, GetNetDemoName());
osDelay(100);
}
while (1)
{
NetDemoTest(PARAM_SERVER_PORT, PARAM_SERVER_ADDR); //开始TCP连接,输入端口号,ip地址
}
printf("disconnect to AP ...\r\n");
// DisconnectWithHotspot(netId);
printf("disconnect to AP done!\r\n");
}
static void NetDemoEntry(void)
{
osThreadAttr_t attr;
attr.name = "NetDemoTask";
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(NetDemoTask, NULL, &attr) == NULL)
{
printf("[NetDemoEntry] Falied to create NetDemoTask!\n");
}
}
SYS_RUN(NetDemoEntry);

①成功连接wifi后,接下来就是创建socket套接字准备进行TCP连接。

int sockfd = socket(AF_INET, SOCK_STREAM, 0); // AF_INET:IP 协议系列。SOCK_STREAM=1:TCP协议

跳转到socket的定义。

struct sockaddr_in serverAddr = {0}; //描述互联网套接字地址的结构体
serverAddr.sin_family = AF_INET; // AF_INET表示IPv4协议
serverAddr.sin_port = htons(port); // 端口号,从主机字节序转为网络字节序
if (inet_pton(AF_INET, host, &serverAddr.sin_addr) <= 0)
{ // 将主机IP地址从“点分十进制”字符串 转化为 标准格式(32位整数)
printf("inet_pton failed!\r\n");
goto do_cleanup;
}

③与主机连接。

// 尝试和目标主机建立连接,连接成功会返回0 ,失败返回 -1
if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
{
printf("connect failed!\r\n");
goto do_cleanup;
}
printf("connect to server %s success!\r\n", host);

④连接成功后,发送数据给目标主机测试是否发送成功。

// 建立连接成功之后,这个TCP socket描述符 —— sockfd 就具有了 “连接状态”,发送、接收 对端都是 connect 参数指定的目标主机和端口
retval = send(sockfd, request, sizeof(request), 0); //发送request给目标主机,成功会返回字符串长度 ,失败返回 -1
if (retval < 0)
{
printf("send request failed!\r\n");
goto do_cleanup;
}
printf("send request{%s} %ld to server done!\r\n", request, retval);

⑤接收服务器发送过来的数据。

retval = recv(sockfd, &response, sizeof(response), 0);//接收目标主机的消息存入response,成功会返回字符串长度 ,失败返回 -1
if (retval <= 0) {
printf("send response from server failed or done, %ld!\r\n", retval);
goto do_cleanup;
}
response[retval] = '\0';
printf("recv response{%s} %ld from server done!\r\n", response, retval);

3、修改代码,实现开关灯操作

①在入口demo_entry_cmsis.c 文件中初始化LED灯的io口。
代码在上文已贴出
②tcp_client_test.c文件。
由上文分析原始的代码可知:开发板(客户端)与主机(服务器)完成一次消息交互后就会关闭socket套接字,再关闭WiFi。
所以可以把关闭套接字的函数(close(sockfd))注释掉,再加个while死循环即可。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "net_demo.h"
#include "net_common.h"
#define LED_TASK_GPIO 9
static char request[] = "Hello";
static char response[128] = "";
void TcpClientTest(const char *host, unsigned short port)
{
ssize_t retval = 0;
int sockfd = socket(AF_INET, SOCK_STREAM, 0); // AF_INET:IP 协议系列。SOCK_STREAM=1:TCP协议

struct sockaddr_in serverAddr = {0}; //描述互联网套接字地址的结构体
serverAddr.sin_family = AF_INET; // AF_INET表示IPv4协议
serverAddr.sin_port = htons(port); // 端口号,从主机字节序转为网络字节序
if (inet_pton(AF_INET, host, &serverAddr.sin_addr) <= 0)
{ // 将主机IP地址从“点分十进制”字符串 转化为 标准格式(32位整数)
printf("inet_pton failed!\r\n");
goto do_cleanup;
}
// 尝试和目标主机建立连接,连接成功会返回0 ,失败返回 -1
if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
{
printf("connect failed!\r\n");
goto do_cleanup;
}
printf("connect to server %s success!\r\n", host);

// 建立连接成功之后,这个TCP socket描述符 —— sockfd 就具有了 “连接状态”,发送、接收 对端都是 connect 参数指定的目标主机和端口
retval = send(sockfd, request, sizeof(request), 0); //发送request给目标主机,成功会返回字符串长度 ,失败返回 -1
if (retval < 0)
{
printf("send request failed!\r\n");
goto do_cleanup;
}
printf("send request{%s} %ld to server done!\r\n", request, retval);
while (1)
{
retval = recv(sockfd, &response, sizeof(response), 0); //接收目标主机的消息存入response,成功会返回字符串长度 ,失败返回 -1
if (retval <= 0)
{
printf("send response from server failed or done, %ld!\r\n", retval);
goto do_cleanup;
}
response[retval] = '\0';
printf("recv response{%s} %ld from server done!\r\n", response, retval);

if (response[0] == 'o' && response[1] == 'n')
{
IoTGpioSetOutputVal(LED_TASK_GPIO, 0); //开灯
printf("The led is on\n");
}
if (response[0] == 'o' && response[1] == 'f' && response[2] == 'f')
{
IoTGpioSetOutputVal(LED_TASK_GPIO, 1); //关灯
printf("The led is off\n");
}
}

do_cleanup:
printf("do_cleanup...\r\n");
// close(sockfd);//关闭套接字
}
CLIENT_TEST_DEMO(TcpClientTest);

四、测试

1.安装netcat(一个非常强大的网络实用工具,可以用它来调试TCP/UDP应用程序)
二选一:

将解压出来的文件全部复制到C:\Windows\System32的文件夹下。

Windows+R cmd 打开命令行。输入nc 命令即可。

2.开始测试

先是PC机开启TCP服务端监听(我选择的是Windows启动netcat)。

-l: 开始监听。

-p:指定端口 (端口号必须保持一致,可在net_params.h文件配置)。

开发板烧录新的固件后rest启动后可观察到服务端接收到了客户端传输过来的数据"hello"。

开发板👇一开始灯是亮的状态。

PC服务端。

服务端输入"off",可让开发板关灯,完成交互。

继续开灯。

五、总结

这次实践中还有一些地方不能完全理解,在net_demo.h文件中。

为什么有这么多斜杠?

testFun是什么?它又是怎样跳转到tcp_client_test.c文件执行TcpClientTest()函数的呢?

想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​​。

来源:51CTO开源基础软件社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯