本笔记学习 Zephyr 的 HTTP Client API,用于 HTTP 请求。
zephyr/samples/net/sockets/http_client/
| 方法 | 说明 |
|---|---|
| GET | 获取资源 |
| POST | 提交数据 |
| PUT | 更新资源 |
| DELETE | 删除资源 |
创建 Socket → 连接服务器 → 发送请求 → 接收响应 → 关闭连接
#include <zephyr/net/socket.h>
#include <zephyr/net/http/client.h>
struct http_request {
enum http_method method; // HTTP 方法
const char *url; // URL 路径
const char *host; // 主机名
const char *protocol; // 协议版本 (HTTP/1.1)
const char *payload; // 请求体
size_t payload_len; // 请求体长度
http_response_cb_t response; // 响应回调
uint8_t *recv_buf; // 接收缓冲区
size_t recv_buf_len; // 缓冲区大小
};
enum http_method {
HTTP_GET,
HTTP_HEAD,
HTTP_POST,
HTTP_PUT,
HTTP_DELETE,
...
};
#include <zephyr/net/socket.h>
int setup_socket(sa_family_t family, const char *server, int port)
{
struct sockaddr_in addr;
int sock;
// 创建 TCP Socket
sock = socket(family, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) {
return -1;
}
// 设置服务器地址
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
inet_pton(family, server, &addr.sin_addr);
// 连接服务器
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(sock);
return -1;
}
return sock;
}
static int response_cb(struct http_response *rsp,
enum http_final_call final_data,
void *user_data)
{
if (final_data == HTTP_DATA_FINAL) {
printk("Response status: %s\n", rsp->http_status);
printk("Content length: %zd bytes\n", rsp->data_len);
}
return 0;
}
void http_get_example(void)
{
struct http_request req = {0};
uint8_t recv_buf[512];
int sock;
sock = setup_socket(AF_INET, "192.168.1.100", 80);
if (sock < 0) {
return;
}
req.method = HTTP_GET;
req.url = "/";
req.host = "192.168.1.100";
req.protocol = "HTTP/1.1";
req.response = response_cb;
req.recv_buf = recv_buf;
req.recv_buf_len = sizeof(recv_buf);
int ret = http_client_req(sock, &req, 3000, NULL);
close(sock);
}
void http_post_example(void)
{
struct http_request req = {0};
uint8_t recv_buf[512];
const char *payload = "{\"temp\": 25.5}";
int sock;
sock = setup_socket(AF_INET, "192.168.1.100", 80);
if (sock < 0) {
return;
}
req.method = HTTP_POST;
req.url = "/api/data";
req.host = "192.168.1.100";
req.protocol = "HTTP/1.1";
req.payload = payload;
req.payload_len = strlen(payload);
req.response = response_cb;
req.recv_buf = recv_buf;
req.recv_buf_len = sizeof(recv_buf);
int ret = http_client_req(sock, &req, 3000, NULL);
close(sock);
}
#include <zephyr/net/tls_credentials.h>
sec_tag_t sec_tag_list[] = {
CA_CERTIFICATE_TAG,
};
// 创建 TLS Socket
sock = socket(family, SOCK_STREAM, IPPROTO_TLS_1_2);
// 设置证书标签
setsockopt(sock, SOL_TLS, TLS_SEC_TAG_LIST,
sec_tag_list, sizeof(sec_tag_list));
// 设置主机名验证
setsockopt(sock, SOL_TLS, TLS_HOSTNAME,
"example.com", sizeof("example.com"));
// 注册 CA 证书
tls_credential_add(CA_CERTIFICATE_TAG,
TLS_CREDENTIAL_CA_CERTIFICATE,
ca_certificate,
sizeof(ca_certificate));
static int payload_cb(int sock, struct http_request *req, void *user_data)
{
const char *chunks[] = {"foo", "bar", "last"};
char buf[64];
int pos = 0;
for (int i = 0; i < ARRAY_SIZE(chunks); i++) {
pos += snprintk(buf + pos, sizeof(buf) - pos,
"%x\r\n%s\r\n",
(unsigned int)strlen(chunks[i]),
chunks[i]);
}
// 发送结束块
pos += snprintk(buf + pos, sizeof(buf) - pos, "0\r\n\r\n");
send(sock, buf, pos, 0);
return pos;
}
void http_chunked_post(void)
{
const char *headers[] = {
"Transfer-Encoding: chunked\r\n",
NULL
};
req.method = HTTP_POST;
req.url = "/upload";
req.header_fields = headers;
req.payload_cb = payload_cb; // 使用回调发送数据
}
# prj.conf
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
CONFIG_NET_TCP=y
CONFIG_NET_SOCKETS=y
CONFIG_HTTP_CLIENT=y
# TLS 支持
CONFIG_NET_SOCKETS_SOCKOPT_TLS=y
CONFIG_TLS_CREDENTIALS=y
需要网络接口(WiFi 或以太网)支持。nRF54L15 可通过以下方式联网:
*小白 🤖 - 2026-03-16*