openharmony hi3861实现网页端控制配置连接wifi

易错点:

每次http通话都需要断开重新accept进行一次tcp连接,不然因为http短连接的缘故无法收到后面的请求。(如:浏览器打开网址,发送了一个get请求,服务器返回,这次可以正常通话。但是当客户端进行提交发送post请求,因为短连接已经断开,服务端就无法接收到了)

没有进行实验长连接,如果想使用长连接自行修改

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


#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_hotspot.h"
#include "lwip/netifapi.h"
#include "lwip/sockets.h"

#define ATTR_STACK_SIZE 10240
#define ZERO 0
#define ONE 1
#define TWO 2
#define THREE 3
#define FOUR 4
#define FIVE 5
#define SEVEN 7
#define TEN 10
#define ONE_HUNDRED 100

static volatile int g_hotspotStarted = 0;        
static const char http_html_hdr[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\nCache-Control: no-cache\r\n\r\n";

static char* g_targetssid[30];
static char* g_targetpassword[30]; 

static const char http_index_html[] =  "<!DOCTYPE html>\n"
                                      "<html lang=\"zh-CN\">\n"
                                      "<head>\n"
                                      "<meta charset=\"UTF-8\">\n"
                                      "</head>\n"
                                      "<body>\n"
                                      "<h1>设置WiFi账号和密码</h1>\n"
                                      "<form id=\"wifiForm\" method=\"POST\">\n\
                                        <input type=\"text\" id=\"ssidInput\" name=\"ssid\" placeholder=\"Enter WiFi SSID\">\n\
                                        <input type=\"password\" id=\"passwordInput\" name=\"password\" placeholder=\"Enter WiFi Password\">\n\
                                        <button type=\"button\" onclick=\"submitForm()\">Submit</button>\n\
                                    </form>\n\
                                    \n\
                                    <script>\n\
                                    function submitForm() {\n\
                                        var ssid = document.getElementById(\"ssidInput\").value;\n\
                                        var password = document.getElementById(\"passwordInput\").value;\n\
                                        var action = \"/ssid=\" + ssid + \"&password=\" + password;\n\
                                        document.getElementById(\"wifiForm\").action = action;\n\
                                        document.getElementById(\"wifiForm\").submit();\n\
                                    }\n\
                                    </script>\n"
                                      "</body>\n"
                                      "</html>";



static void OnHotspotStateChanged(int state)
{
    printf("OnHotspotStateChanged: %d.\r\n", state);
    if (state == WIFI_HOTSPOT_ACTIVE) {
        g_hotspotStarted = 1;
    } else {
        g_hotspotStarted = 0;
    }
}

static volatile int g_joinedStations = 0;

static void PrintStationInfo(StationInfo* info)
{
    if (!info) return;
    static char macAddress[32] = {0};
    unsigned char* mac = info->macAddress;
    if (sprintf(macAddress, "%02X:%02X:%02X:%02X:%02X:%02X",
        mac[ZERO], mac[ONE], mac[TWO], mac[THREE], mac[FOUR], mac[FIVE]) == TRUE) {
    printf("OK");
}
    printf(" PrintStationInfo: mac=%s, reason=%d.\r\n", macAddress, info->disconnectedReason);
}

static void OnHotspotStaJoin(StationInfo* info)
{
    g_joinedStations++;
    PrintStationInfo(info);
    printf("+OnHotspotStaJoin: active stations = %d.\r\n", g_joinedStations);
}

static void OnHotspotStaLeave(StationInfo* info)
{
    g_joinedStations--;
    PrintStationInfo(info);
    printf("-OnHotspotStaLeave: active stations = %d.\r\n", g_joinedStations);
}

WifiEvent g_defaultWifiEventListener = {
    .OnHotspotStaJoin = OnHotspotStaJoin,
    .OnHotspotStaLeave = OnHotspotStaLeave,
    .OnHotspotStateChanged = OnHotspotStateChanged,
}; 

static struct netif* g_iface = NULL;

int StartHotspot(const HotspotConfig* config)
{
    WifiErrorCode errCode = WIFI_SUCCESS;

    errCode = RegisterWifiEvent(&g_defaultWifiEventListener);
    printf("RegisterWifiEvent: %d\r\n", errCode);

    errCode = SetHotspotConfig(config);
    printf("SetHotspotConfig: %d\r\n", errCode);

    g_hotspotStarted = 0;
    errCode = EnableHotspot();
    printf("EnableHotspot: %d\r\n", errCode);

    while (!g_hotspotStarted) {
        osDelay(TEN);
    }
    printf("g_hotspotStarted = %d.\r\n", g_hotspotStarted);

    g_iface = netifapi_netif_find("ap0");
    if (g_iface) {
        ip4_addr_t ipaddr;
        ip4_addr_t gateway;
        ip4_addr_t netmask;

        IP4_ADDR(&ipaddr,  192, 168, 1, 5);     /* input your IP for example: 192.168.1.1 */
        IP4_ADDR(&gateway, 192, 168, 1, 1);     /* input your gateway for example: 192.168.1.1 */
        IP4_ADDR(&netmask, 255, 255, 255, 0);   /* input your netmask for example: 255.255.255.0 */
        err_t ret = netifapi_netif_set_addr(g_iface, &ipaddr, &netmask, &gateway);
        printf("netifapi_netif_add: %d\r\n", ret);

        ret = netifapi_dhcps_stop(g_iface); // 海思扩展的HDCP服务接口
        printf("netifapi_dhcps top: %d\r\n", ret);

        ret = netifapi_dhcps_start(g_iface, 0, 0); // 海思扩展的HDCP服务接口
        printf("netifapi_dhcp tart: %d\r\n", ret);
    }
    return errCode;
}

void StopHotspot(void)
{
    if (g_iface) {
        err_t ret = netifapi_dhcps_stop(g_iface);  // 海思扩展的HDCP服务接口
        printf("netifapi_dhcps top: %d\r\n", ret);
    }

    WifiErrorCode errCode = UnRegisterWifiEvent(&g_defaultWifiEventListener);
    printf("UnRegisterWifiEvent: %d\r\n", errCode);

    errCode = DisableHotspot();
    printf("EnableHotspot: %d\r\n", errCode);
}

static int DisposeNetMessageType(char* buf)
{
    int buflen = strlen(buf);
    /* 判断是不是HTTP的GET命令*/
    if (    buf[0]=='G' &&
            buf[1]=='E' &&
            buf[2]=='T' &&
            buf[3]==' ' &&
            buf[4]=='/' )
    {
        return 0;
    }
    else if (buf[0]=='P'&&buf[1]=='O'
                 &&buf[2]=='S'&&buf[3]=='T')
    {
        return 1;
    }   
    return -1;
}

static void WifiHotspotTask(int *arg)
{
    (void)arg;
    WifiErrorCode errCode;
    HotspotConfig config = {0};
    // 配置作为AP热点的ssid和key
    if (strcpy(config.ssid,  "HiSpark-AP")) {
}
    if (strcpy(config.preSharedKey, "12345678")) {
}
    config.securityType = WIFI_SEC_TYPE_PSK;
    config.band = HOTSPOT_BAND_TYPE_2G;
    config.channelNum = SEVEN;

    osDelay(TEN);

    printf("starting AP ...\r\n");
    // 开启热点
    errCode = StartHotspot(&config);
    printf("StartHotspot: %d\r\n", errCode);
    // 热点开启时长为60s
    int timeout = 60;

    osDelay(ONE_HUNDRED);

    //建立tcp连接
    ssize_t retval = 0;
    int backlog = 1;
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
    int connfd = -1;
    

    struct sockaddr_in clientAddr = {0};
    socklen_t clientAddrLen = sizeof(clientAddr);
    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(80);  // 端口号,从主机字节序转为网络字节序
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 允许任意主机接入, 0.0.0.0

    retval = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); // 绑定端口    
    if (retval < 0) {
        printf("bind failed, %ld!\r\n", retval);
        close(sockfd);
    }
    printf("bind to port %u success!\r\n", 80);

    retval = listen(sockfd, backlog); // 开始监听
    if (retval < 0) {
        printf("listen failed!\r\n");
        printf("do_cleanup...\r\n");
        close(sockfd);
    }
    printf("listen with %d backlog success!\r\n", backlog);

    // 接受客户端连接,成功会返回一个表示连接的 socket , clientAddr 参数将会携带客户端主机和端口信息 ;失败返回 -1
    // 此后的 收、发 都在 表示连接的 socket 上进行;之后 sockfd 依然可以继续接受其他客户端的连接,
    //  UNIX系统上经典的并发模型是“每个连接一个进程”——创建子进程处理连接,父进程继续接受其他客户端的连接
    //  鸿蒙liteos-a内核之上,可以使用UNIX的“每个连接一个进程”的并发模型
    //     liteos-m内核之上,可以使用“每个连接一个线程”的并发模型

    while (1) {
        static int i=1;

        connfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
        if (connfd < 0) {
            printf("accept failed, %d, %d\r\n", connfd, errno);
            printf("do_cleanup...\r\n");
            close(sockfd);
        }
       
        // 后续 收、发 都在 表示连接的 socket 上进行;
        char request[1024] = "";
        retval = recv(connfd, request, sizeof(request), 0 );
        if (retval < 0) {
            printf("recv request failed, %ld!\r\n", retval);
  
            close(sockfd);
            return;
        }

        printf("%s", request);
        int messagetype = DisposeNetMessageType(request);
        if(messagetype == 0)//get请求
        {
                retval = send(connfd, http_html_hdr, strlen(http_html_hdr), 0);
                if (retval <= 0) {
                    //printf("send response failed, %ld!\r\n", retval);
          
                    close(sockfd);
                }

                retval = send(connfd, http_index_html, strlen(http_index_html), 0);
                if (retval <= 0) {
                    //printf("222222222send response failed, %ld!\r\n", retval);
               
                    close(sockfd);
                }
        }
        else if (messagetype == 1) //post请求
        {
                //printf("send response failed, %ld!\r\n", retval);
                char *ssid_start = strstr(request, "ssid="); // 找到ssid参数的起始位置
                char *password_start = strstr(request, "password="); // 找到password参数的起始位置
                
                if (ssid_start && password_start) { // 确保找到了ssid和password参数
                    ssid_start += strlen("ssid="); // 跳过参数名
                    password_start += strlen("password="); // 跳过参数名
                    // 查找参数值的结束位置(&符号或字符串结束符)
                    char *ssid_end = strchr(ssid_start, '&');
                    char *password_end = strchr(password_start, ' ');
                    // 如果找不到&符号,表示参数值是字符串的末尾
                    if (!ssid_end) ssid_end = strchr(ssid_start, '\0');
                    if (!password_end) password_end = strchr(password_start, '\0');

                    // 提取参数值并打印                
                    strncpy(g_targetssid,ssid_start,(int)(ssid_end - ssid_start));
                    strncpy(g_targetpassword,password_start,(int)(password_end - password_start));
                    printf("SSID: %s\n",  g_targetssid);
                    printf("Password: %s\n", g_targetpassword);
                } else {
                    printf("SSID and/or Password not found in request.\n");
                }      

                retval = send(connfd, http_html_hdr, strlen(http_html_hdr), 0);
                if (retval <= 0) {
                    close(sockfd);
                }

                retval = send(connfd, http_index_html, strlen(http_index_html), 0);
                if (retval <= 0) {
                    //printf("222222222send response failed, %ld!\r\n", retval);
               
                    close(sockfd);
                }
        } 
        else //未知消息
        {
            //printf("111111:recv requesty%s\n", request);
        }

        /* 关闭 */
        close(connfd);

        printf("\n++++++++++++++++++++i:%d \n",i++);
    }
    // 可以通过串口工具发送:AT+PING=192.168.xxx.xxx(如手机连接到该热点后的IP)去ping连接到该热点的设备的IP地址
    printf("stop AP ...\r\n");
    // 关闭热点
    StopHotspot();
    printf("stop AP ...\r\n");
}

static void WifiHotspotDemo(void)
{
    osThreadAttr_t attr;
    // 初始化相关配置
    attr.name = "WifiHotspotTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = ATTR_STACK_SIZE;
    attr.priority = osPriorityNormal;

    if (osThreadNew(WifiHotspotTask, NULL, &attr) == NULL) {
        printf("[WifiHotspotDemo] Failed to create WifiHotspotTask!\n");
    }
}

SYS_RUN(WifiHotspotDemo);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丈原

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值