本文主要是介绍HI3861学习笔记(22)——UDP客户端,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、TCP与UDP优缺点
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。
TCP通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。
5、TCP对系统资源要求较多,UDP对系统资源要求较少。
二、API说明
以下 UDP 接口位于 vendor\hisi\hi3861\hi3861\third_party\lwip_sack\include\sockets.h。
业务BUILD.gn中包含路径
include_dirs = ["//utils/native/lite/include","//kernel/liteos_m/components/cmsis/2.0","//base/iot_hardware/interfaces/kits/wifiiot_lite","//foundation/communication/interfaces/kits/wifi_lite/wifiservice","//vendor/hisi/hi3861/hi3861/third_party/lwip_sack/include/",]
socket()
bind()
accept()
shutdown()
getpeername()
getsockopt()
&setsockopt()
close()
read()
,readv()
,write()
,writev()
recv()
send()
,sendmsg()
,sendto()
select()
fcntl()
三、UDP客户端
3.1 主要流程
3.1.1 第一步:新建socket
在网络编程中所需要进行的第一件事情就是创建一个socket,无论是客户端还是服务器端,都需要创建一个socket,该函数返回socket文件描述符,类似于文件描述符。socket是一个结构体,被创建在内核中。
//在sock_fd 进行监听,在 new_fd 接收新的链接
int sock_fd;//创建socket
if((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{perror("create socket failed!\r\n");exit(1);
}
3.1.2 第二步:配置将要连接的服务器信息(端口和IP)
按道理服务器的地址选择
255.255.255.255
,意思是不指定局域网内的某一设备,局域网所有的设备如果监听了这个端口号,那么都可以收到hi3861发来的消息。但是实际好像就只能填UDP服务器的地址,而已只能发送,不能接收。
#define UDP_PROT 8888int addr_length;//服务器的地址信息
struct sockaddr_in send_addr;
socklen_t addr_length = sizeof(send_addr);//初始化预连接的服务端地址
send_addr.sin_family = AF_INET;
send_addr.sin_port = htons(UDP_PROT);
send_addr.sin_addr.s_addr = inet_addr("192.168.31.225");
addr_length = sizeof(send_addr);
3.1.3 第三步:发送数据
sendto()
用来将数据由指定的socket传给对方主机。参数s为已建好连线的socket。参数msg指向欲连线的数据内容,参数flags一般设0。
static const char *send_data = "Hello! I'm BearPi-HM_Nano UDP Client!\r\n";//发送数据到服务远端
sendto(sock_fd, send_data, strlen(send_data), 0, (struct sockaddr *)&send_addr, addr_length);
3.1.4 第四步:接收数据
char recvBuf[512];while (1)
{bzero(recvBuf, sizeof(recvBuf));...//线程休眠一段时间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);
}
3.2 配置SSID和密码连接WIFI创建TCP客户端
wifi_connect.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>#include "lwip/netif.h"
#include "lwip/netifapi.h"
#include "lwip/ip4_addr.h"
#include "lwip/api_shell.h"#include "cmsis_os2.h"
#include "hos_types.h"
#include "wifi_device.h"
#include "wifiiot_errno.h"
#include "ohos_init.h"#define DEF_TIMEOUT 15
#define ONE_SECOND 1#define SELECT_WIFI_SECURITYTYPE WIFI_SEC_TYPE_PSK static void WiFiInit(void);
static void WaitSacnResult(void);
static int WaitConnectResult(void);
static void OnWifiScanStateChangedHandler(int state, int size);
static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo *info);
static void OnHotspotStaJoinHandler(StationInfo *info);
static void OnHotspotStateChangedHandler(int state);
static void OnHotspotStaLeaveHandler(StationInfo *info);static int g_staScanSuccess = 0;
static int g_ConnectSuccess = 0;
static int ssid_count = 0;
WifiEvent g_wifiEventHandler = {0};
WifiErrorCode error;#define SELECT_WLAN_PORT "wlan0"int WifiConnect(const char *ssid, const char *psk)
{WifiScanInfo *info = NULL;unsigned int size = WIFI_SCAN_HOTSPOT_LIMIT;static struct netif *g_lwip_netif = NULL;osDelay(200);printf("<--System Init-->\r\n");//初始化WIFIWiFiInit();//使能WIFIif (EnableWifi() != WIFI_SUCCESS){printf("EnableWifi failed, error = %d\r\n", error);return -1;}//判断WIFI是否激活if (IsWifiActive() == 0){printf("Wifi station is not actived.\r\n");return -1;}//分配空间,保存WiFi信息info = malloc(sizeof(WifiScanInfo) * WIFI_SCAN_HOTSPOT_LIMIT);if (info == NULL){return -1;}//轮询查找WiFi列表do{//重置标志位ssid_count = 0;g_staScanSuccess = 0;//开始扫描Scan();//等待扫描结果WaitSacnResult();//获取扫描列表error = GetScanInfoList(info, &size);}while(g_staScanSuccess != 1);//打印WiFi列表printf("********************\r\n");for(uint8_t i = 0; i < ssid_count; i++){printf("no:%03d, ssid:%-30s, rssi:%5d\r\n", i+1, info[i].ssid, info[i].rssi/100);}printf("********************\r\n");//连接指定的WiFi热点for(uint8_t i = 0; i < ssid_count; i++){if (strcmp(ssid, info[i].ssid) == 0){int result;printf("Select:%3d wireless, Waiting...\r\n", i+1);//拷贝要连接的热点信息WifiDeviceConfig select_ap_config = {0};strcpy(select_ap_config.ssid, info[i].ssid);strcpy(select_ap_config.preSharedKey, psk);select_ap_config.securityType = SELECT_WIFI_SECURITYTYPE;if (AddDeviceConfig(&select_ap_config, &result) == WIFI_SUCCESS){if (ConnectTo(result) == WIFI_SUCCESS && WaitConnectResult() == 1){printf("WiFi connect succeed!\r\n");g_lwip_netif = netifapi_netif_find(SELECT_WLAN_PORT);break;}}}if(i == ssid_count-1){printf("ERROR: No wifi as expected\r\n");while(1) osDelay(100);}}//启动DHCPif (g_lwip_netif){dhcp_start(g_lwip_netif);printf("begain to dhcp\r\n");}//等待DHCPfor(;;){if(dhcp_is_bound(g_lwip_netif) == ERR_OK){printf("<-- DHCP state:OK -->\r\n");//打印获取到的IP信息netifapi_netif_common(g_lwip_netif, dhcp_clients_info_show, NULL);break;}printf("<-- DHCP state:Inprogress -->\r\n");osDelay(100);}osDelay(100);return 0;
}static void WiFiInit(void)
{printf("<--Wifi Init-->\r\n");g_wifiEventHandler.OnWifiScanStateChanged = OnWifiScanStateChangedHandler;g_wifiEventHandler.OnWifiConnectionChanged = OnWifiConnectionChangedHandler;g_wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinHandler;g_wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveHandler;g_wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedHandler;error = RegisterWifiEvent(&g_wifiEventHandler);if (error != WIFI_SUCCESS){printf("register wifi event fail!\r\n");}else{printf("register wifi event succeed!\r\n");}
}static void OnWifiScanStateChangedHandler(int state, int size)
{if (size > 0){ssid_count = size;g_staScanSuccess = 1;}printf("callback function for wifi scan:%d, %d\r\n", state, size);return;
}static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo *info)
{if (info == NULL){printf("WifiConnectionChanged:info is null, stat is %d.\n", state);}else{if (state == WIFI_STATE_AVALIABLE){g_ConnectSuccess = 1;}else{g_ConnectSuccess = 0;}}
}static void OnHotspotStaJoinHandler(StationInfo *info)
{(void)info;printf("STA join AP\n");return;
}static void OnHotspotStaLeaveHandler(StationInfo *info)
{(void)info;printf("HotspotStaLeave:info is null.\n");return;
}static void OnHotspotStateChangedHandler(int state)
{printf("HotspotStateChanged:state is %d.\n", state);return;
}static void WaitSacnResult(void)
{int scanTimeout = DEF_TIMEOUT;while (scanTimeout > 0){sleep(ONE_SECOND);scanTimeout--;if (g_staScanSuccess == 1){printf("WaitSacnResult:wait success[%d]s\n", (DEF_TIMEOUT - scanTimeout));break;}}if (scanTimeout <= 0){printf("WaitSacnResult:timeout!\n");}
}static int WaitConnectResult(void)
{int ConnectTimeout = DEF_TIMEOUT;while (ConnectTimeout > 0){sleep(ONE_SECOND);ConnectTimeout--;if (g_ConnectSuccess == 1){printf("WaitConnectResult:wait success[%d]s\n", (DEF_TIMEOUT - ConnectTimeout));break;}}if (ConnectTimeout <= 0){printf("WaitConnectResult:timeout!\n");return 0;}return 1;
}
wifi_connect.h
#ifndef __WIFI_CONNECT_H__
#define __WIFI_CONNECT_H__int WifiConnect(const char *ssid,const char *psk);#endif /* __WIFI_CONNECT_H__ */
四、完整代码
编译时在业务BUILD.gn中包含路径
static_library("myapp") {sources = ["wifi_connect.c","hello_world.c"]cflags = [ "-Wno-unused-variable" ]cflags += [ "-Wno-unused-but-set-variable" ]cflags += [ "-Wno-unused-parameter" ]include_dirs = ["//utils/native/lite/include","//kernel/liteos_m/components/cmsis/2.0","//base/iot_hardware/interfaces/kits/wifiiot_lite","//foundation/communication/interfaces/kits/wifi_lite/wifiservice","//vendor/hisi/hi3861/hi3861/third_party/lwip_sack/include/",]
}
hello_world.c
#include <stdio.h>
#include <unistd.h>#include "ohos_init.h"
#include "cmsis_os2.h"#include "wifi_device.h"
#include "lwip/netifapi.h"
#include "lwip/api_shell.h"
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include "lwip/sockets.h"
#include "wifi_connect.h"#define UDP_PROT 3333//在sock_fd 进行监听,在 new_fd 接收新的链接
int sock_fd;int addr_length;
static const char *send_data = "Hello! I'm BearPi-HM_Nano UDP Client!\r\n";//服务器的地址信息
struct sockaddr_in send_addr;static void UDPClientTask(void)
{socklen_t addr_length = sizeof(send_addr);char recvBuf[512];//连接WifiWifiConnect("406", "82069909");//创建socketif ((sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1){perror("create socket failed!\r\n");exit(1);}//初始化预连接的服务端地址send_addr.sin_family = AF_INET;send_addr.sin_port = htons(UDP_PROT);send_addr.sin_addr.s_addr = inet_addr("192.168.31.225");addr_length = sizeof(send_addr);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);}//关闭这个 socketclosesocket(sock_fd);
}static void UDPClientDemo(void)
{osThreadAttr_t attr;attr.name = "UDPClientTask";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)UDPClientTask, NULL, &attr) == NULL){printf("[UDPClientDemo] Falied to create UDPClientTask!\n");}
}APP_FEATURE_INIT(UDPClientDemo);
查看打印:
• 由 Leung 写于 2022 年 3 月 15 日
• 参考:【鸿蒙2.0设备开发教程】小熊派HarmonyOS 鸿蒙·季 开发教程
这篇关于HI3861学习笔记(22)——UDP客户端的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!