搜索
bottom↓
回复: 9

一个基于lwip netconn的HTTP Client 【标题不合格,帖子改得面目全非,被封锁ID】

[复制链接]

出0入0汤圆

发表于 2018-6-16 09:09:21 来自手机 | 显示全部楼层 |阅读模式

基于netconn的HTTP Client,配合cjson应该能完成很多很多东西了.源码:


******************************************************************************
  * @file    webclient.c
  * @author  TaterLi
  * @brief   LwIP Netconn HTTP/1.0 Client (GET/POST)
  ******************************************************************************
        Example:
        extern struct netif gnetif;
        cJSON *root, *sub_root;
        cJSON *origin_price, *real_price;
        uint8_t *abuf;
        void web_view(void *arg)
        {
                        int err = HTTP_OK;
                        const char postVar[] = "origin_price=1&real_price=3";
                        while(gnetif.ip_addr.addr == 0x00)
                        {
                                        vTaskDelay(1000);
                        }
                        while(1)
                        {
                                        err = WebClient("http://ticks.applinzi.com/lwip/post.php", postVar, &abuf);
                                        if(abuf != NULL && err == HTTP_OK)
                                        {
                                                        root = cJSON_Parse((const char *)abuf);
                                                        origin_price = cJSON_GetObjectItem( root , "origin_price" );
                                                        real_price = cJSON_GetObjectItem( root , "real_price" );
                                                        vPortFree(abuf);
                                                        cJSON_Delete(root);
                                                        vTaskDelay(100);
                                        }
                                        err = WebClient("http://ticks.applinzi.com/lwip/get.php?origin_price=2&real_price=6", NULL, &abuf);
                                        if(abuf != NULL && err == HTTP_OK)
                                        {
                                                        root = cJSON_Parse((const char *)abuf);
                                                        origin_price = cJSON_GetObjectItem( root , "origin_price" );
                                                        real_price = cJSON_GetObjectItem( root , "real_price" );
                                                        vPortFree(abuf);
                                                        cJSON_Delete(root);
                                                        vTaskDelay(100);
                                        }
                                        err = WebClient("http://ticks.applinzi.com/lwip/mixed.php?origin_price=5", postVar, &abuf);
                                        if(abuf != NULL && err == HTTP_OK)
                                        {
                                                        root = cJSON_Parse((const char *)abuf);
                                                        sub_root = cJSON_GetObjectItem( root , "get" );
                                                        origin_price = cJSON_GetObjectItem( sub_root , "origin_price" );
                                                        vPortFree(abuf);
                                                        cJSON_Delete(root);
                                                        vTaskDelay(100);
                                        }
                                        vTaskDelay(1000);
                        }
        }
  */

#include "webclient.h"

extern struct netif gnetif;

int8_t WebClient(const char *url, const char *post, uint8_t **pageBuf)
{

    uint16_t i, j, k;
    uint8_t *server_addr = NULL;
    uint8_t *web_addr = NULL;
    ip_addr_t server_ip;
    struct netconn *conn = NULL;
    struct netbuf *inBuf = NULL;
    struct pbuf *q;
    char *request = NULL;
    uint16_t recvPos = 0;
    uint8_t *recvBuf;
    err_t err_msg;

    while(gnetif.ip_addr.addr == 0x00)
    {
        return HTTP_ROUTE_NOT_FOUND;
    }

    if(strncmp((const char *)url, "http://", 7) == 0)                 /* 只处理http协议 */
    {
        server_addr = pvPortMalloc(strlen(url) - 7);
        if(server_addr == NULL) return HTTP_OUT_OF_RAM;
        /* 1)提取服务器部分 */
        for(i = 4; url[i]; ++i)
        {
            if (url[i] == ':' && url[i + 1] == '/' && url[i + 2] == '/')
            {
                for (i = i + 3, j = 0; url[i] > 32 && url[i] < 127 && url[i] != '/';
                        ++i, ++j)
                {
                    server_addr[j] = url[i];
                    if (url[i] == '@') /* 服务器基础认证符号,我们做不了,遇到就错误. */
                    {
                        return HTTP_AUTH_NOT_SUPPORT;
                    }
                }
                server_addr[j] = '\0';

                web_addr = pvPortMalloc(strlen(url) - 7 - strlen((const char *)server_addr));
                if(web_addr == NULL) return HTTP_OUT_OF_RAM;

                for (k = 7 + j; k < (strlen(url)); k++) /* 后半部分提取 */
                {
                    web_addr[k - 7 - j] = url[k];
                }

                web_addr[k - 7 - j] = '\0';

                while (--j)
                {
                    if (server_addr[j] == ':')
                    {
                        server_addr[j] = '\0';
                    }
                }
            }

        }

        if(strlen((const char *)server_addr) < 2) /* 最短网址3.cn */
        {
            vPortFree(server_addr);
            if(web_addr == NULL) vPortFree(web_addr); /* 这么短,还不一定提取到了这个. */
            return HTTP_SERVER_ADDR_ERROR;
        }

        /* 2)查询IP */
        netconn_gethostbyname((const char *)server_addr, &server_ip);

        /* 3)构造访问头 */
        request = pvPortMalloc(strlen(url) + 1024); /* 头所需内存大小. */
        if(request == NULL) return HTTP_OUT_OF_RAM;

        if(post != NULL)
            sprintf(request, "POST %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (lwip;STM32) TaterLi\r\nContent-Length: %d\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n%s", web_addr, server_addr, strlen(post), post);
        else
            sprintf(request, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (lwip;STM32) TaterLi\r\n\r\n", web_addr, server_addr);
        vPortFree(server_addr);
        if(web_addr != NULL)
        {
            /* 万一没提取到,就是NULL,如果是NULL,那么也不用继续了. */
            vPortFree(web_addr);
        }
        else
        {
            vPortFree(request);
            return HTTP_NOT_VALID_ADDR;
        }

        /* 4)开始访问 */
        conn = netconn_new(NETCONN_TCP);
        err_msg = netconn_connect(conn, &server_ip, 80); /* 目前也只能支持80端口,比较常用,不考虑特殊情况. */
                               
        if (err_msg == ERR_OK)
        {
            netconn_write(conn, request, strlen((char *)request), NETCONN_COPY);
            vPortFree(request);
            conn->recv_timeout = 3000;
            recvPos = 0;

            if((err_msg = netconn_recv(conn, &inBuf)) == ERR_OK)   /* HTTP 1.0 天然不拆包,里面有alloc操作. */
            {
                recvBuf = pvPortMalloc(inBuf->p->tot_len);
                if(recvBuf == NULL)
                {
                    return HTTP_OUT_OF_RAM;
                }
                for(q = inBuf->p; q != NULL; q = q->next) //遍历完整个pbuf链表
                {
                    memcpy(recvBuf + recvPos, q->payload, q->len);
                    recvPos += q->len;
                }
            }

            netconn_close(conn);
            netconn_delete(conn);
            netbuf_delete(inBuf);

            if(err_msg != ERR_OK) return HTTP_OUT_OF_RAM;

            /* 5)分析数据(分析HTTP头,暂时不打算支持301之类的)        */
            for(i = 0; recvBuf[i]; ++i)
            {
                if (recvBuf[i] == '2' && recvBuf[i + 1] == '0' && recvBuf[i + 2] == '0')
                {
                    /* 证明200 OK */
                    for(; recvBuf[i]; ++i)
                    {
                        /* 响应头的结束也是两个回车 */
                        if(recvBuf[i] == '\r' && recvBuf[i + 1] == '\n' && recvBuf[i + 2] == '\r' && recvBuf[i + 3] == '\n')
                        {
                            /* 6)复制正文内容 */
                            i += 4;
                            k = strlen((const char *)recvBuf) - i;
                            if(k == 0) return HTTP_NO_CONTENT;
                            *pageBuf = pvPortMalloc(k);
                            if(*pageBuf == NULL)
                            {
                                vPortFree(recvBuf);
                                return HTTP_OUT_OF_RAM;
                            }
                            memcpy((char *)*pageBuf, (const char *)recvBuf + i, k); /* 用HTTP1.0是没http chunked response的.方便处理,否则还要分段接收网页,大的网页反正MCU也接不下. */
                            vPortFree(recvBuf);
                            return HTTP_OK;
                        }
                    }
                }
            }

            if(recvBuf != NULL)        vPortFree(recvBuf);

            return HTTP_NOT_200OK;
        }
        else
        {
            return HTTP_SERVER_REFUSE;
        }

    }
    else
    {
        return HTTPS_NOT_SUPPORT;
    }
}

出0入0汤圆

 楼主| 发表于 2018-6-16 09:12:52 来自手机 | 显示全部楼层
上面说的8字节一组,16字节一组,是不是OSMemCreate两次,一次8字节的,一次16字节的?

出0入0汤圆

发表于 2018-6-16 10:11:23 | 显示全部楼层
这段文字是你引用的?里面不是已经说了吗?它的内存管理实质上编译的时候就是建了一个全局二维数组,申请的时候都是从这个数组里取用,大小是和数组长度有关的。
头像被屏蔽

出0入0汤圆

发表于 2018-6-16 12:40:40 来自手机 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

 楼主| 发表于 2018-6-16 12:47:54 | 显示全部楼层
armok 发表于 2018-6-16 12:40
“ucos内存管理”不是合格的标题。

违反版规11。请立即阅读版规(点击进入: http://www.amobbs.com/thread- ...

谢谢提醒,之前手机编辑的,疏忽了。

标题已改。

头像被屏蔽

出0入0汤圆

发表于 2018-6-16 12:50:13 来自手机 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
头像被屏蔽

出0入0汤圆

发表于 2018-6-16 12:51:19 来自手机 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

发表于 2018-6-16 18:01:50 | 显示全部楼层
lwip用起来的时候还是存在一些问题的。但是基本可以解决大部分问题。我之前用LWIP的时候,因为经常开销TCP结果TCP的创建数量达到一定数量,LWIP就会奔溃,我已经注意清楚相关内存和指针了。不知道为什么

出0入22汤圆

发表于 2018-6-16 18:27:55 来自手机 | 显示全部楼层
jnode 发表于 2018-6-16 18:01
lwip用起来的时候还是存在一些问题的。但是基本可以解决大部分问题。我之前用LWIP的时候,因为经常开销TCP ...

你是有大量的连接经常连接和断开么?
头像被屏蔽

出0入0汤圆

发表于 2018-6-17 02:06:37 来自手机 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-21 00:22

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表