243 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include <stdio.h>          // 标准输入输出
 | 
						||
#include <unistd.h>         // POSIX标准接口
 | 
						||
#include <errno.h>          // 错误码
 | 
						||
#include <string.h>         // 字符串处理(操作字符数组)
 | 
						||
 | 
						||
#include "lwip/sockets.h"   // lwIP TCP/IP协议栈:Socket API
 | 
						||
#include "ohos_init.h"      // 用于初始化服务(services)和功能(features)
 | 
						||
#include "cmsis_os2.h"      // CMSIS-RTOS API V2
 | 
						||
#include "oled_ssd1306.h" 
 | 
						||
#include "json_parser.h"    // JSON解析器
 | 
						||
#include "wifi_connecter.h" // WiFi连接器
 | 
						||
 | 
						||
 | 
						||
 | 
						||
extern int control_flag ;
 | 
						||
 | 
						||
// 要发送的数据
 | 
						||
static char request[] = "connecting";
 | 
						||
 | 
						||
// 要接收的数据
 | 
						||
char response[128] = "";
 | 
						||
 | 
						||
// 全局变量存储解析后的命令
 | 
						||
JsonCommand g_current_command = {0};
 | 
						||
 | 
						||
// 发送IP地址到服务器
 | 
						||
void SendIpToServer(const char *host, unsigned short port) {
 | 
						||
    char ip_buffer[32] = {0};
 | 
						||
    char message_buffer[128] = {0};
 | 
						||
    
 | 
						||
    // 获取本机IP地址
 | 
						||
    if (GetLocalIpAddress(ip_buffer, sizeof(ip_buffer)) != 0) {
 | 
						||
        printf("Failed to get local IP address\r\n");
 | 
						||
        return;
 | 
						||
    }
 | 
						||
    
 | 
						||
    // 创建IP消息
 | 
						||
    if (CreateIpMessage(message_buffer, sizeof(message_buffer), ip_buffer) != 0) {
 | 
						||
        printf("Failed to create IP message\r\n");
 | 
						||
        return;
 | 
						||
    }
 | 
						||
    
 | 
						||
    // 创建UDP socket
 | 
						||
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
 | 
						||
    if (sockfd < 0) {
 | 
						||
        printf("Failed to create socket\r\n");
 | 
						||
        return;
 | 
						||
    }
 | 
						||
    
 | 
						||
    struct sockaddr_in toAddr = {0};
 | 
						||
    toAddr.sin_family = AF_INET;
 | 
						||
    toAddr.sin_port = htons(port);
 | 
						||
    
 | 
						||
    if (inet_pton(AF_INET, host, &toAddr.sin_addr) <= 0) {
 | 
						||
        printf("inet_pton failed!\r\n");
 | 
						||
        lwip_close(sockfd);
 | 
						||
        return;
 | 
						||
    }
 | 
						||
    
 | 
						||
    // 发送IP地址消息
 | 
						||
    ssize_t retval = sendto(sockfd, message_buffer, strlen(message_buffer), 0, 
 | 
						||
                           (struct sockaddr *)&toAddr, sizeof(toAddr));
 | 
						||
    
 | 
						||
    if (retval < 0) {
 | 
						||
        printf("Failed to send IP message!\r\n");
 | 
						||
    } else {
 | 
						||
        printf("IP message sent: %s\r\n", message_buffer);
 | 
						||
    }
 | 
						||
    
 | 
						||
    lwip_close(sockfd);
 | 
						||
}
 | 
						||
 | 
						||
/// @brief UDP客户端测试函数
 | 
						||
/// @param host UDP服务端IP地址
 | 
						||
/// @param port UDP服务端端口
 | 
						||
void UdpClientTest(const char *host, unsigned short port)
 | 
						||
{
 | 
						||
    // 用于接收Socket API接口返回值
 | 
						||
    ssize_t retval = 0;
 | 
						||
    // 创建一个UDP Socket,返回值为文件描述符
 | 
						||
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
 | 
						||
    if (sockfd < 0) {
 | 
						||
        printf("创建socket失败!\r\n");
 | 
						||
        return;
 | 
						||
    }
 | 
						||
    
 | 
						||
    // 用于设置服务端的地址信息
 | 
						||
    struct sockaddr_in toAddr = {0};
 | 
						||
    // 用于设置本地绑定的地址信息
 | 
						||
    struct sockaddr_in localAddr = {0};
 | 
						||
 | 
						||
    // 使用IPv4协议
 | 
						||
    toAddr.sin_family = AF_INET;
 | 
						||
    localAddr.sin_family = AF_INET;
 | 
						||
 | 
						||
    // 端口号,从主机字节序转为网络字节序
 | 
						||
    toAddr.sin_port = htons(port);
 | 
						||
    localAddr.sin_port = htons(port);  // 绑定到相同端口接收数据
 | 
						||
    localAddr.sin_addr.s_addr = INADDR_ANY;  // 绑定到所有可用的网络接口
 | 
						||
 | 
						||
    // 将服务端IP地址从"点分十进制"字符串,转化为标准格式(32位整数)
 | 
						||
    if (inet_pton(AF_INET, host, &toAddr.sin_addr) <= 0)
 | 
						||
    {
 | 
						||
        // 转化失败
 | 
						||
        printf("inet_pton failed!\r\n");    // 输出日志
 | 
						||
        lwip_close(sockfd);
 | 
						||
        return;    
 | 
						||
    }
 | 
						||
 | 
						||
    // 绑定本地端口,这样才能接收数据
 | 
						||
    printf("绑定本地端口 %d...\r\n", port);
 | 
						||
    if (bind(sockfd, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0) {
 | 
						||
        printf("绑定端口失败!错误: %d\r\n", errno);
 | 
						||
        lwip_close(sockfd);
 | 
						||
        return;
 | 
						||
    }
 | 
						||
    printf("端口绑定成功!\r\n");
 | 
						||
 | 
						||
    // 发送设备IP地址到服务器
 | 
						||
    SendIpToServer(sockfd, &toAddr);
 | 
						||
 | 
						||
    // 发送数据
 | 
						||
    // UDP socket是 "无连接的",因此每次发送都必须先指定目标主机和端口,主机可以是多播地址
 | 
						||
    // 发送数据的时候,使用本地随机端口N
 | 
						||
    // 
 | 
						||
    // 参数:
 | 
						||
    // s:socket文件描述符
 | 
						||
    // dataptr:要发送的数据
 | 
						||
    // size:要发送的数据的长度,最大65332字节
 | 
						||
    // flags:消息传输标志位
 | 
						||
    // to:目标的地址信息
 | 
						||
    // tolen:目标的地址信息长度
 | 
						||
    // 
 | 
						||
    // 返回值:
 | 
						||
    // 发送的字节数,如果出错,返回-1
 | 
						||
    printf("发送连接消息到服务器...\r\n");
 | 
						||
    retval = sendto(sockfd, request, sizeof(request), 0, (struct sockaddr *)&toAddr, sizeof(toAddr));
 | 
						||
 | 
						||
    // 检查接口返回值,小于0表示发送失败
 | 
						||
    if (retval < 0)
 | 
						||
    {
 | 
						||
        // 发送失败
 | 
						||
        printf("发送消息失败!错误: %d\r\n", errno);   // 输出日志
 | 
						||
        lwip_close(sockfd);
 | 
						||
        return;                
 | 
						||
    }
 | 
						||
 | 
						||
    // 发送成功
 | 
						||
    // 输出日志
 | 
						||
    printf("发送UDP消息成功: {%s} %ld 字节\r\n", request, retval);
 | 
						||
    
 | 
						||
    // 显示等待接收状态
 | 
						||
    printf("开始监听UDP消息,等待来自 %s 的数据...\r\n", host);
 | 
						||
    
 | 
						||
    // 用于记录发送方的地址信息(IP地址和端口号)
 | 
						||
    struct sockaddr_in fromAddr = {0};
 | 
						||
 | 
						||
    // 用于记录发送方的地址信息长度
 | 
						||
    socklen_t fromLen = sizeof(fromAddr);
 | 
						||
 | 
						||
    // 在本地随机端口N上面接收数据
 | 
						||
    // UDP socket是 “无连接的”,因此每次接收时并不知道消息来自何处,通过fromAddr参数可以得到发送方的信息(主机、端口号)
 | 
						||
    // device\hisilicon\hispark_pegasus\sdk_liteos\third_party\lwip_sack\include\lwip\sockets.h -> lwip_recvfrom
 | 
						||
    //
 | 
						||
    // 参数:
 | 
						||
    // s:socket文件描述符
 | 
						||
    // buffer:接收数据的缓冲区的地址
 | 
						||
    // length:接收数据的缓冲区的长度
 | 
						||
    // flags:消息接收标志位
 | 
						||
    // address:发送方的地址信息
 | 
						||
    // address_len:发送方的地址信息长度
 | 
						||
    //
 | 
						||
    // 返回值:
 | 
						||
    // 接收的字节数,如果出错,返回-1
 | 
						||
    while (1)
 | 
						||
    {
 | 
						||
        // 清空接收缓冲区
 | 
						||
        memset(response, 0, sizeof(response));
 | 
						||
        
 | 
						||
        retval = lwip_recvfrom(sockfd, response, sizeof(response) - 1, 0, (struct sockaddr *)&fromAddr, &fromLen);
 | 
						||
 | 
						||
        // 检查接口返回值,小于0表示接收失败
 | 
						||
        if (retval <= 0)
 | 
						||
        {
 | 
						||
            // 接收失败,或者收到0长度的数据(忽略掉)
 | 
						||
            printf("recvfrom failed or abort, %ld, %d!\r\n", retval, errno);    // 输出日志
 | 
						||
            continue;  // 继续接收,不要关闭socket                                                
 | 
						||
        }
 | 
						||
 | 
						||
        // 接收成功
 | 
						||
        // 末尾添加字符串结束符'\0',以便后续的字符串操作
 | 
						||
        response[retval] = '\0';
 | 
						||
 | 
						||
        // 输出日志 - 显示所有收到的消息
 | 
						||
        printf("=== 收到UDP消息 ===\r\n");
 | 
						||
        printf("消息内容: {%s}\r\n", response);
 | 
						||
        printf("消息长度: %ld 字节\r\n", retval);
 | 
						||
        printf("发送方IP: %s\r\n", inet_ntoa(fromAddr.sin_addr));
 | 
						||
        printf("发送方端口: %d\r\n", ntohs(fromAddr.sin_port));
 | 
						||
        printf("==================\r\n");
 | 
						||
        
 | 
						||
        // 尝试解析JSON命令
 | 
						||
        JsonCommand temp_cmd = {0};
 | 
						||
        if (ParseJsonCommand(response, &temp_cmd) == 0) {
 | 
						||
            printf("JSON解析成功: cmd=%d, text=%s\r\n", temp_cmd.cmd, temp_cmd.text);
 | 
						||
            
 | 
						||
            // 保存解析的命令
 | 
						||
            g_current_command = temp_cmd;
 | 
						||
            
 | 
						||
            // 根据命令类型设置控制标志
 | 
						||
            if (temp_cmd.cmd >= 1 && temp_cmd.cmd <= 4) {
 | 
						||
                control_flag = temp_cmd.cmd;
 | 
						||
                printf("设置控制标志为: %d\r\n", control_flag);
 | 
						||
            } else {
 | 
						||
                printf("无效的命令类型: %d\r\n", temp_cmd.cmd);
 | 
						||
            }
 | 
						||
        } else {
 | 
						||
            printf("JSON解析失败,尝试旧格式命令\r\n");
 | 
						||
            
 | 
						||
            // 兼容旧的字符串命令格式
 | 
						||
            if(strlen(response) > 10) {
 | 
						||
                control_flag = 2;
 | 
						||
                g_current_command.cmd = 0;  // 标记为旧命令
 | 
						||
                printf("设置为复杂字符串命令,控制标志: %d\r\n", control_flag);
 | 
						||
            } else if(strcmp(response,"T:on") == 0) {
 | 
						||
                control_flag = 1;
 | 
						||
                g_current_command.cmd = 0;  // 标记为旧命令
 | 
						||
                printf("设置为开启命令,控制标志: %d\r\n", control_flag);
 | 
						||
            } else if(strcmp(response,"T:off") == 0) {
 | 
						||
                control_flag = 0;
 | 
						||
                g_current_command.cmd = 0;  // 标记为旧命令
 | 
						||
                printf("设置为关闭命令,控制标志: %d\r\n", control_flag);
 | 
						||
            } else {
 | 
						||
                printf("未识别的命令格式: %s\r\n", response);
 | 
						||
            }
 | 
						||
        }
 | 
						||
        
 | 
						||
        sleep(1);
 | 
						||
    }
 | 
						||
    // 关闭socket
 | 
						||
    lwip_close(sockfd);
 | 
						||
}
 |