Lwip-2.1.3, Http client添加post方法

文章介绍了如何基于Lwip2.1.3的httpclient源码,通过最小改动添加POST方法。主要涉及定义POST请求的基础报文格式,修改httpc_create_request_string函数以支持POST,并在httpc_connection_t结构体中添加新成员以存储POST相关参数。
摘要由CSDN通过智能技术生成
Lwip-2.1.3源码中提供了http client接口,但是默认只有GET方法,如何基于源码最小改动添加POST方法?
lwip/src/apps/http/http_client.c

GET 和 POST 报文区别这里不表。

1、http_client.c中GET的基础报文:

	/* GET request basic */
	#define HTTPC_REQ_11 "GET %s HTTP/1.1\r\n" /* URI */\
    "User-Agent: %s\r\n" /* User-Agent */ \
    "Accept: */*\r\n" \
    "Connection: Close\r\n" /* we don't support persistent connections, yet */ \
    "\r\n"
	#define HTTPC_REQ_11_FORMAT(uri) HTTPC_REQ_11, uri, HTTPC_CLIENT_AGENT

	/* GET request with host */
	#define HTTPC_REQ_11_HOST "GET %s HTTP/1.1\r\n" /* URI */\
    "User-Agent: %s\r\n" /* User-Agent */ \
    "Accept: */*\r\n" \
    "Host: %s\r\n" /* server name */ \
    "Connection: Close\r\n" /* we don't support persistent connections, yet */ \
    "\r\n"
	#define HTTPC_REQ_11_HOST_FORMAT(uri, srv_name) HTTPC_REQ_11_HOST, uri, HTTPC_CLIENT_AGENT, srv_name

	/* GET request with proxy */
	#define HTTPC_REQ_11_PROXY "GET http://%s%s HTTP/1.1\r\n" /* HOST, URI */\
    "User-Agent: %s\r\n" /* User-Agent */ \
    "Accept: */*\r\n" \
    "Host: %s\r\n" /* server name */ \
    "Connection: Close\r\n" /* we don't support persistent connections, yet */ \
    "\r\n"
	#define HTTPC_REQ_11_PROXY_FORMAT(host, uri, srv_name) HTTPC_REQ_11_PROXY, host, uri, HTTPC_CLIENT_AGENT, srv_name

	/* GET request with proxy (non-default server port) */
	#define HTTPC_REQ_11_PROXY_PORT "GET http://%s:%d%s HTTP/1.1\r\n" /* HOST, host-port, URI */\
    "User-Agent: %s\r\n" /* User-Agent */ \
    "Accept: */*\r\n" \
    "Host: %s\r\n" /* server name */ \
    "Connection: Close\r\n" /* we don't support persistent connections, yet */ \
    "\r\n"
	#define HTTPC_REQ_11_PROXY_PORT_FORMAT(host, host_port, uri, srv_name) HTTPC_REQ_11_PROXY_PORT, host, host_port, uri, HTTPC_CLIENT_AGENT, srv_name

类比写出 POST的基础报文格式(post标准报文格式自行查找资料):

/* POST request basic */  
#define HTTPC_REQ_11_POST "POST %s HTTP/1.1\r\n" /* URI */\
    "User-Agent: %s\r\n" /* User-Agent */ \
    "Accept: */*\r\n" \
    "Content-Type: application/x-www-form-urlencoded\r\n" \
    "Content-Length: %d\r\n" \
    "Connection: Close\r\n" /* we don't support persistent connections, yet */\
    "\r\n" \
    "%s"
      
#define HTTPC_REQ_11_FORMAT_POST(uri, arglen, args)  HTTPC_REQ_11_POST, uri, HTTPC_CLIENT_AGENT, arglen, args
      
/* POST request with host */
#define HTTPC_REQ_11_HOST_POST "POST %s HTTP/1.1\r\n" /* URI */\
    "User-Agent: %s\r\n" /* User-Agent */ \
    "Accept: */*\r\n" \
    "Host: %s\r\n" /* server name */ \
    "Content-Type: application/x-www-form-urlencoded\r\n" \
    "Content-Length: %d\r\n" \
    "Connection: Close\r\n" /* we don't support persistent connections, yet */ \
    "\r\n" \
    "%s"
      
#define HTTPC_REQ_11_HOST_FORMAT_POST(uri, srv_name, arglen, args) HTTPC_REQ_11_HOST, uri, HTTPC_CLIENT_AGENT, srv_name, arglen, args

Content-Type可以有多种,可以根据不同需求调整。
这里没有写出post使用代理的报文(因为没用到),需要的话可以参照GET的代理报文。
2、生成完整报文函数:
httpclient模块使用 httpc_create_request_string 函数生成 GET 报文,所以可以从这个函数着手。

static int
httpc_create_request_string(const httpc_connection_t *settings, const char* server_name, int server_port, const char* uri,
                            int use_host, char *buffer, size_t buffer_size)
{
  if (settings->use_proxy) {
    LWIP_ASSERT("server_name != NULL", server_name != NULL);
    if (server_port != HTTP_DEFAULT_PORT) {
      return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_PORT_FORMAT(server_name, server_port, uri, server_name));
    } else {
      return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_FORMAT(server_name, uri, server_name));
    }
  } else if (use_host) {
    LWIP_ASSERT("server_name != NULL", server_name != NULL);
    return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT(uri, server_name));
  } else {
    return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT(uri));
  }
}

这里先撇开代理不看,添加使用post的分支:

static int
httpc_create_request_string(const httpc_connection_t *settings, const char* server_name, int server_port, const char* uri,
                            int use_host, char *buffer, size_t buffer_size)
{
  if (settings->use_proxy) {
    LWIP_ASSERT("server_name != NULL", server_name != NULL);
    if (server_port != HTTP_DEFAULT_PORT) {
      return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_PORT_FORMAT(server_name, server_port, uri, server_name));
    } else {
      return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_FORMAT(server_name, uri, server_name));
    }
  } else if (use_host) {
    LWIP_ASSERT("server_name != NULL", server_name != NULL);
    if (USE_POST){
		return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT_POST(uri, server_name, ARGLENS, ARGS));
	}
    return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT(uri, server_name));
  } else {
  	if (USE_POST){
    	return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT_POST(uri, ARGLENS, ARGS));
    }
    return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT(uri));
  }
}

思考:

	USE_POST, ARGLENS, ARGS 如何来?

3、修改 httpc_connection_t
从函数中可以看出判断是否使用代理使用的是 settings->use_proxy 。
settings类型:

typedef struct _httpc_connection {
  ip_addr_t proxy_addr;
  u16_t proxy_port;
  u8_t use_proxy;
  /* @todo: add username:pass? */

#if LWIP_ALTCP
  altcp_allocator_t *altcp_allocator;
#endif

  /* this callback is called when the transfer is finished (or aborted) */
  httpc_result_fn result_fn;
  /* this callback is called after receiving the http headers
     It can abort the connection by returning != ERR_OK */
  httpc_headers_done_fn headers_done_fn;
} httpc_connection_t;

同样可以在该结构体中添加触发使用 post 的成员变量,类似如下:

typedef struct _httpc_connection {
  ip_addr_t proxy_addr;
  u16_t proxy_port;
  u8_t use_proxy;
  /* @todo: add username:pass? */

#if LWIP_ALTCP
  altcp_allocator_t *altcp_allocator;
#endif

  /* this callback is called when the transfer is finished (or aborted) */
  httpc_result_fn result_fn;
  /* this callback is called after receiving the http headers
     It can abort the connection by returning != ERR_OK */
  httpc_headers_done_fn headers_done_fn;
  
  u8_t  use_post;
  u8_t  arglen;
  u8_t* args;
} httpc_connection_t;
总结:

修改后的_httpc_connection 定义如下:

typedef struct _httpc_connection {
  ip_addr_t proxy_addr;
  u16_t proxy_port;
  u8_t use_proxy;
  /* @todo: add username:pass? */

#if LWIP_ALTCP
  altcp_allocator_t *altcp_allocator;
#endif

  /* this callback is called when the transfer is finished (or aborted) */
  httpc_result_fn result_fn;
  /* this callback is called after receiving the http headers
     It can abort the connection by returning != ERR_OK */
  httpc_headers_done_fn headers_done_fn;
  
  u8_t  use_post;
  u8_t  arglen;
  u8_t* args;
} httpc_connection_t;

修改后的httpc_create_request_string 函数如下:

static int
httpc_create_request_string(const httpc_connection_t *settings, const char* server_name, int server_port, const char* uri,
                            int use_host, char *buffer, size_t buffer_size)
{
  if (settings->use_proxy) {
    LWIP_ASSERT("server_name != NULL", server_name != NULL);
    if (server_port != HTTP_DEFAULT_PORT) {
      return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_PORT_FORMAT(server_name, server_port, uri, server_name));
    } else {
      return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_FORMAT(server_name, uri, server_name));
    }
  } else if (use_host) {
    LWIP_ASSERT("server_name != NULL", server_name != NULL);
    if (settings->use_post){
		return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT_POST(uri, server_name, settings->arglen, settings->args));
	}
    return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT(uri, server_name));
  } else {
  	if (settings->use_post){
    	return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT_POST(uri, settings->arglen, settings->args));
    }
    return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT(uri));
  }
}
使用:
static 
err_t http_rev_func(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
  LWIP_PLATFORM_DIAG(("this is  http_rev_func\r\n"));
  pbuf_free(p);
  return ERR_OK;
}
 
 httpc_connection_t setting = {    .use_proxy = 0,
                                   .result_fn = NULL,
                                   .headers_done_fn = NULL};
// 使用 GET 方法                                   
httpc_get_file(&ser_ipaddr, 8080,"/index.html", NULL, http_rev_func, NULL, NULL);

// 使用 POST 方法
setting.use_post = 1;
setting.arglen = 0;
setting.args = NULL;
httpc_get_file(&ser_ipaddr, 8080,"/index.html", &setting , http_rev_func, NULL, NULL);
lwip(轻量级IP协议栈)是一个开源的TCP/IP协议栈,旨在用于嵌入式系统和实时应用。移植lwip 2.1.3到特定的嵌入式系统需要以下步骤: 1. 下载和解压缩lwip软件包:首先,从lwip官方网站上下载最新版本的lwip 2.1.3软件包。然后,将软件包解压缩到本地目录。 2. 配置lwip:进入lwip软件包所在的目录,找到lwipopts.h头文件。通过修改该头文件中的宏定义,根据嵌入式系统的需求配置lwip。可能需要设置的选项包括:IP地址、子网掩码、网关地址、最大数据包长度等。 3. 移植硬件驱动:lwip需要硬件驱动程序来与底层网络接口进行通信。嵌入式系统通常有自己的网络接口硬件,所以需要移植特定的硬件驱动程序。根据硬件接口和规范,实现网络驱动程序和相关函数。 4. 移植操作系统适配层(optional):如果嵌入式系统使用操作系统,如RTOS(实时操作系统),则需要移植操作系统适配层以支持lwip的多线程和并发操作。根据具体的操作系统规范,实现适配层函数和功能。 5. 编译和链接:使用适当的交叉编译工具链,将lwip源代码以及硬件驱动程序和适配层代码编译成目标平台的可执行文件。然后,将生成的目标文件链接到嵌入式系统的应用程序中。 6. 调试和测试:在嵌入式系统上运行编译和链接后的 lwip软件,并进行相应的调试和测试。确保lwip在特定的嵌入式环境下能够正常工作,并实现所期望的网络功能。 总之,移植lwip 2.1.3到嵌入式系统需要进行配置、移植硬件驱动程序、可能的操作系统适配层移植、编译和链接等步骤。通过这些步骤,lwip可以在嵌入式系统上实现TCP/IP网络功能,并提供轻量级的网络通信能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值