往期知识点记录:
- 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
- OpenHarmony之分布式软总线json_payload.c(一)
- OpenHarmony之分布式软总线json_payload.c(二)
- OpenHarmony之分布式软总线json_payload.c(三)
- OpenHarmony之分布式软总线json_payload.c(四)
- OpenHarmony之分布式软总线nstackx_common.c分析
- OpenHarmony之分布式软总线coap_discover.c(一)
- OpenHarmony之分布式软总线coap_discover.c(二)
- 持续更新中……
前言
这部分将分析当设备收到对端设备发现报文时,需要发送响应报文的过程。
接收与响应coap设备发现
/*
函数功能: 获取服务发现信息
函数参数:
buf : 指向保存有服务信息的数据缓冲区
size : 数据缓冲区大小
deviceInfo: 用来保存设备信息
remoteUrlPtr : 指向用来保存URL的缓存区
详细:
1. 判断buf是否为空
2. buf具有数据那么就分配一个同样大小的空间,并将buf中的数据拷贝到newbuf中,且将buf指针指向newbuf
3. 调用json_payload.c中ParseServiceDiscover解析出buf所指缓存区的数据(对端设备的 设备信息,设备功能,设备IP)保存在deviceInfo,url保存在由remoteUrlPtr指向的在url的缓存区
4. 释放newbuf空间
*/
int GetServiceDiscoverInfo(const uint8_t *buf, size_t size, DeviceInfo *deviceInfo, char **remoteUrlPtr)
{
uint8_t *newBuf = NULL;
if (size <= 0) {
return NSTACKX_EFAILED;
}
//包含数据
if (buf[size - 1] != '\0') {
//newBuf 分配空间并初始化为1
newBuf = (uint8_t *)calloc(1, size + 1);
if (newBuf == NULL) {
return NSTACKX_ENOMEM;
}·
if (memcpy_s(newBuf, size + 1, buf, size) != EOK) {
goto L_COAP_ERR;
}
buf = newBuf;
}
//解析出设备发现信息
if (ParseServiceDiscover(buf, deviceInfo, remoteUrlPtr) != NSTACKX_EOK) {
goto L_COAP_ERR;
}
if (newBuf != NULL) {
free(newBuf);
}
return NSTACKX_EOK;
L_COAP_ERR:
if (newBuf != NULL) {
free(newBuf);
}
return NSTACKX_EFAILED;
}
/*
函数功能: 对接收到的消息进行服务发现响应
函数功能: pkt: 接收到的coap数据包
函数返回值 : 无
详细:
1. 声明remoteurl 来存储对端url,deiceInfo保存对端设备信息
2. 调用GetServiceDiscoverInfo解析出device信息和对端url
3. 创建字符数组wifiIpAddr用来保存对端ip地址
4. 将点分IP转换为二进制网络字节序IP,并保存在wifiIpAddr
5. 发送响应报文,最后释放remoteUrl
*/
void PostServiceDiscover(const COAP_Packet *pkt)
{
char *remoteUrl = NULL;
DeviceInfo deviceInfo;
if (pkt == NULL) {
return;
}
//为deiveInfo分配空间
(void)memset_s(&deviceInfo, sizeof(deviceInfo), 0, sizeof(deviceInfo));
if (GetServiceDiscoverInfo(pkt->payload.buffer, pkt->payload.len, &deviceInfo, &remoteUrl) != NSTACKX_EOK) {
return;
}
char wifiIpAddr[NSTACKX_MAX_IP_STRING_LEN];
(void)memset_s(wifiIpAddr, sizeof(wifiIpAddr), 0, sizeof(wifiIpAddr)); //初始化为0
(void)inet_ntop(AF_INET, &deviceInfo.netChannelInfo.wifiApInfo.ip, wifiIpAddr, sizeof(wifiIpAddr));
if (remoteUrl != NULL) {
CoapResponseService(pkt, remoteUrl, wifiIpAddr);
free(remoteUrl);
}
}
/*
函数功能: 处理读事件
函数参数 : fd: 可读就绪的套接字
函数返回值: 无
详细:
1. 分配一个1*(COAP_MAX_PDU_SIZE + 1) 接收缓存区
2. 调用coap_socket.c中CoapSocketRecv函数接收数据
3. 如果接收错误,释放接收缓冲区空间
4. 创建一个COAP_Packet,用于保存从接收缓冲区解析出来的coap数据包
5. 最后需要对接收到的数据做出响应
*/
static void HandleReadEvent(int fd)
{
int socketFd = fd;
unsigned char *recvBuffer = calloc(1, COAP_MAX_PDU_SIZE + 1);
if (recvBuffer == NULL) {
return;
}
ssize_t nRead;
nRead = CoapSocketRecv(socketFd, recvBuffer, COAP_MAX_PDU_SIZE);
if ((nRead == 0) || (nRead < 0 && errno != EAGAIN &&
errno != EWOULDBLOCK && errno != EINTR)) {
free(recvBuffer);
return;
}
COAP_Packet decodePacket;
(void)memset_s(&decodePacket, sizeof(COAP_Packet), 0, sizeof(COAP_Packet));
decodePacket.protocol = COAP_UDP;
COAP_SoftBusDecode(&decodePacket, recvBuffer, nRead);
PostServiceDiscover(&decodePacket);
free(recvBuffer);
}
/*
函数功能: 接收并处理收到的数据
详细:
1. 声明fd_set结构来表示一组等待检查的套接口,用于select 端口复用,可读文件描述符
2. 获取服务端socket
3. 将set清零使集合中不含任何fd,将服务socket接入到集合
4. 需要检查的文件描述字个数(即检查到fd_set的第几位),用来检查可读性的一组文件描述字readSet
5. 若有就绪描述符,则返回就绪描述符数目,检查readSet中对应serverFd的位是否被设置,如果该位被设置之后,那么readSet中与serverFd对应的位无关的位均清0
6. 最后处理读事件
*/
static void CoapReadHandle(unsigned int uwParam1, unsigned int uwParam2, unsigned int uwParam3, unsigned int uwParam4)
{
//这些参数在函数体中没有用到,但是为了防止编译器警告
(void)uwParam1;
(void)uwParam2;
(void)uwParam3;
(void)uwParam4;
int ret;
//fd_set结构来表示一组等待检查的套接口,用于select 端口复用,可读文件描述符
fd_set readSet;
//获取服务端socket
int serverFd = GetCoapServerSocket();
SOFTBUS_PRINT("[DISCOVERY] CoapReadHandle coin select begin\n");
while (g_terminalFlag) { //设备为终端设备
FD_ZERO(&readSet);//将set清零使集合中不含任何fd
FD_SET(serverFd, &readSet); //将服务socket接入到集合
//需要检查的文件描述字个数(即检查到fd_set的第几位),用来检查可读性的一组文件描述字readSet
ret = select(serverFd + 1, &readSet, NULL, NULL, NULL);
//若有就绪描述符,则返回就绪描述符数目
if (ret > 0) {
//检查readSet中对应serverFd的位是否被设置,如果该位被设置之后,那么readSet中与serverFd对应的位无关的位均清0,
if (FD_ISSET(serverFd, &readSet)) {
//处理读事件
HandleReadEvent(serverFd);
}
} else {
SOFTBUS_PRINT("[DISCOVERY]ret:%d,error:%d\n", ret, errno);
}
}
SOFTBUS_PRINT("[DISCOVERY] CoapReadHandle exit\n");
}