You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
朱天龙 (Armink) 426db43365
Merge pull request #18 from chenyong111/master
完善日志信息,完善 TLS 处理方式
7 years ago
.gitignore Initial commit 8 years ago
LICENSE Initial commit 8 years ago
README.md 【增加】说明文档。 7 years ago
SConscript 【修复】适配网络框架,添加有关时间操作头文件支持。 7 years ago
webclient.c 【重构】修改接口名称与定义方式,添加 POST 相关函数,删除无用函数定义 7 years ago
webclient.h 【重构】修改接口名称与定义方式,添加 POST 相关函数,删除无用函数定义 7 years ago
webclient_file.c 【重构】修改接口名称与定义方式,添加 POST 相关函数,删除无用函数定义 7 years ago

README.md

WebClient介绍

本章节是webclient的使用和API说明描述了如何使用webclient与WEB Server通信。

webclient设计简介

webclient是HTTP协议的客户端工具提供与WEB Server通信的基本功能。 一般而言设备端运行RT-Thread开源实时系统并使用webclient提供的API与 HTTP 服务器交互。

webclient会话结构体定义

webclient底层操作接口都使用了统一的webclient客户端会话: struct webclient_session,它被定义成:

struct webclient_session
{
    /* the session socket */
    int socket;
    /* the response code of HTTP request */
    int response;

    /* transfer encoding */
    char *transfer_encoding;
    int chunk_sz;
    int chunk_offset;

    /* content_type of HTTP response */
    char *content_type;
    /* content_length of HTTP response */
    int  content_length;

    /* last modified timestamp of resource */
    char *last_modified;

    /* location */
    char *location;

    /* server host */
    char *host;
    /* HTTP request */
    char *request;

    /* private for webclient session. */

    /* position of reading */
    unsigned int position;

    /* remainder of content reading */
    size_t content_length_remainder;
};

其中当服务端有回应时:

  • response会存储服务端的相应代码如果成功服务端回复:200详细描述请参考 HTTP 状态码表。
  • content_type服务端提供的内容类型。
  • content_length服务端返回的数据长度。

webclient API说明

webclient会话接口

webclient底层接口定义了面向http这层的公共访问接口流方式接口可以基于这层接口进行底层的http操作。

webclient_open

struct webclient_session* webclient_open(const char* URI);
  • 功能: 打开一个webclient客户端

  • 参数1: URI 指向相应的网址,可以包括域名,特殊的端口号等。例如: URI = "http://www.test.com:8080/index.html"

  • 返回值: 成功返回一个webclient客户端会话失败返回RT_NULL

webclient_open用于打开一个webclient会话默认方法为get。 返回时客户端就已经解析了http返回头部里面有status_code及resp_len。 根据这些信息可以做进一步处理如使用webclient_read读取服务器返回的数据。

webclient_open_header

struct webclient_session* 
webclient_open_header(const char* URI, int method,
				      const char* header, size_t header_sz);
  • 功能: 在打开会话时可以加入一些自定义的HTTP请求头信息

  • 参数1: URI指向相应的网址可以包括域名特殊的端口号等。例如: URI = "http://www.test.com:8080/index.html"

  • 参数2: method定义了打开URI的方法当前支持GETWEBCLIENT_GET或POSTWEBCLIENT_POST)

  • 参数3: header信息例如:

"Host: www.host.com\r\n"
"User-Agent: YourAgent\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"

header信息中必须使用"CR+LF"(回车+换行)作为分隔符和结束符。 header中每项应该符合HTTP的协议标准。 而一些基本的信息例如HostHTTP/1.0等信息如果header中不存在webclient会自动添加。

  • 返回值: 成功返回一个webclient客户端会话失败返回RT_NULL

webclient_open_header用于打开一个webclient会话method由用户指定。 相比webclient_open接口webclient_open_header可以自定义请求的header。

webclient_close

int webclient_close(struct webclient_session* session);
  • 功能: 关闭一个webclient客户端
  • 参数1: session指向要关闭的webclient客户端会话
  • 返回值: 0

webclient_close用于关闭webclient一个会话。

webclient数据接口

webclient_read

int webclient_read (struct webclient_session* session, 
					unsigned char *buffer, size_t size);
  • 功能: 从http连接中读取一段数据非服务端响应的http header
  • 参数1: session一个webclient客户端会话
  • 参数2: buffer保存从http连接中读取的数据的缓冲区
  • 参数3: size每次读取的最大数据
  • 返回值: 成功返回读到的数据长度;失败返回负数

webclient_read从webclient会话中读取数据。

webclient_write

int webclient_write(struct webclient_session* session, 
					const unsigned char *buffer, size_t size);
  • 功能: 向http连接发送一段数据
  • 参数1: session一个webclient客户端会话
  • 参数2: buffer要发送的数据的缓冲区
  • 参数3: size要发送的数据的长度
  • 返回值: 成功发送的数据长度

webclient_write向webclient会话写入数据。

webclient应用接口

webclient传输数据

int webclient_transfer(const char* URI, const char* header, 
                         size_t header_sz,
						 const char* data, size_t data_sz,
						 char *result, size_t result_sz);
  • 功能: 向指定的URI传递数据data同时也设置附加的HTTP请求头部信息为header)并读取结果到result缓冲区中。函数返回读取到的数据长度。
  • 参数1: URI指向相应的网址可以包括域名特殊的端口号等。
  • 参数2: header信息。
  • 参数4: header信息的长度。
  • 参数4: data要发送的数据
  • 参数5: size要发送的数据的长度
  • 参数6: result用于保存从服务器接收到的数据缓冲区当不需要保存时可以为空。
  • 参数7: result_sz用于保存从服务器接收到的数据缓冲区长度。
  • 返回值: 成功发送的数据长度

webclient_transfer会自动创建一个session并在传输完成后关闭session。

webclient文件下载

int webclient_get_file(const char* URI, const char* filename);

这个函数用于从URI下载一个文件并保存到filename指定的路径上。保存的文件仅包括服务端提供的文件而不包括HTTP响应的头部信息。例如下面的例子:

/*
* 服务端的文件test.txt放于webroot目录下(web路径的根目录下),其内容是:
* "this is a test.\n"
*/
void test(void)
{
	/* 下载test.txt文件 */
	webclient_get_file("http://www.test.com/test.txt", "/test.txt");
}
/*
* 保存在本地根目录的test.txt文件的内容是:
* "this is a test.\n"
*/

webclient文件上传

int webclient_post_file(const char* URI, 
                   const char* filename, 
				   const char* form_data);

这个函数用于从filename路径的文件中读取数据并向URI以POST方法发送这个文件的 内容; 例如用于上传的form是:

<form action="uploader.php" method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>

参数form_data可以填充服务端关心的类型信息例如:

"name=\"file\"; filename=\"test.txt\""

这样服务端可以得到filename的值是“test.txt”。

webclient测试及示例程序

下面的例子是一个使用webclient底层接口的例子

#include <http_client.h>
#include <dfs_posix.h>
#define BUF_SZ 4096
void webclient_test(void)
{
	int fd = -1;
	int offset;
	rt_uint8_t* ptr = RT_NULL;
	struct webclient_session* session = RT_NULL; /* webclient客户端会话 */

	session = webclient_open("http://www.test.com/index.html");
	if (session == RT_NULL)
	{
		rt_kprintf("open website failed.\n");
		goto __exit;
	}

	if (session->response != 200)
	{
		/* 服务端给出错误的响应 */
		rt_kprintf("wrong response: %d\n", session->response);
		goto __exit;
	}

	if (strcmp(session->content_type, "text/html") != 0)
	{
		/* 不是自己关心的内容类别,退出 */
		rt_kprintf("context_type: %d\n", session->content_type);
		goto __exit;
	}

	fd = open("/index.html", O_WRONLY | O_CREAT, 0);
	if (fd < 0)
	{
		/* 创建文件出错,返回 */
		rt_kprintf("open file failed\n");
		goto __exit;
	}

	/* 分配需要的缓冲 */
	ptr = rt_malloc (BUF_SZ);
	if (ptr == RT_NULL)
	{
		rt_kprintf("out of memory\n");
		goto __exit;
	}

	if (session->content_length == 0)
	{
		/* 如果服务端未给出数据内容长度,读取数据直到服务端关闭连接 */
		while (1)
		{
		length = webclient_read(session, ptr, BUF_SZ);
		if (length > 0) write(fd, ptr, length);
		else break;
		}
	}
	else
	{
		for (offset = 0; offset < session->content_length; )
		{
			/* 从连接读取数据 */
			length = webclient_read(session, ptr,
			session->content_length - offset > BUF_SZ?
			BUF_SZ:session->content_length - offset);
			/* 写入到文件中 */
			if (length > 0) write(fd, ptr, length);
			else break;
			/* 挪动偏移位置 */
			offset += length;
		}
	}

__exit: /* 退出出口 */
	if (session != RT_NULL) webclient_close(session);
	if (fd >= 0) close(fd);
	if (ptr != RT_NULL) rt_free(ptr);
	return;
}