ESP32开发之路(8)—ESP32通过DNS连接到百度
ESP32开发之路(8)—ESP32通过DNS连接到百度本次开发环境是在Ubuntu下的,使用的模块是GOOUUU-ESP32,在Win10下使用VSCode远程编辑项目。代码使用来自esp-idf的例程。一、准备可以先看一下:C语言网络编程(4)— 通过DNS连接到百度-优化和在Win10上使用SSH远程连接Linux搭建VSCode开发环境在上个工程(ESP32开发之路(7)—ESP3...
ESP32开发之路(8)—ESP32通过DNS连接到百度
本次开发环境是在Ubuntu下的,使用的模块是GOOUUU-ESP32,在Win10下使用VSCode远程编辑项目。代码使用来自esp-idf的例程。
一、准备
可以先看一下:C语言网络编程(4)— 通过DNS连接到百度-优化和在Win10上使用SSH远程连接Linux搭建VSCode开发环境
在上个工程(ESP32开发之路(7)—ESP32作为TCP客户端连接到局域网的PC机)的基础上,将tcp_client_task任务重写为dns_client_task。
二、DNS解析
在esp-idf里的getaddrinfo()
好像是被阉割了,有一些功能是没有被实现的,毕竟ESP32只是一个MCU而已。
经过的我的测试,发现解析后对于有多个IP地址的域名也只能得到一个IP地址,而且第二个参数好像不支持服务名称,如"ftp"、"http"等,只支持端口号字串,不过如果域名有IPv6地址,将ai_family
设置为AF_INET6
也能查到Iv6地址。
首先,添加我们需要用到的头文件
#include "lwip/dns.h"
定义一个hints结构体,用来设置函数的getaddrinfo()的使用方式:
// 1、定义一个hints结构体,用来设置函数的getaddrinfo()的使用方式
const struct addrinfo hints = {
.ai_family = AF_INET, /* 指定返回地址的协议簇,AF_INET(IPv4)、AF_INET6(IPv6)、AF_UNSPEC(IPv4 and IPv6)*/
.ai_socktype = SOCK_STREAM, /* 设定返回地址的socket类型,流式套接字 */
};
使用getaddrinfo()开始解析了,注意,第二个参数要十进制的端口号(“8080”)字符串
// 2、使用getaddrinfo()开始解析,定义一个struct addrinfo结构体指针,用来获取解析结果
struct addrinfo *result;
int err;
err = getaddrinfo("www.163.com", "80", &hints, &result);
if(err != 0) /* 返回值不为0,函数执行失败*/
printf("getaddrinfo err: %d \n",err);
将获取到的信息打印出来
// 3、将获取到的信息打印出来
char buf[100]; /* 用来存储IP地址字符串 */
struct sockaddr_in *ipv4 = NULL; /* IPv4地址结构体指针 */
if(result->ai_family == AF_INET)
{
ipv4 = (struct sockaddr_in *)result->ai_addr;
inet_ntop(result->ai_family, &ipv4->sin_addr, buf, sizeof(buf));
printf("[IPv4-%d]%s [port]%d \n",ipv4_cnt,buf,ntohs(ipv4->sin_port));
}
else
printf("got IPv4 err !!!\n");
使用完我们需要释放addrinfo 内存
// 4、释放addrinfo 内存
freeaddrinfo(result);
编译,烧录,运行成功
我们尝试将域名换成“www.163.com”,即网易的域名,然后ai_family都换成AF_INET6,可以看到,获取到了IPv6地址
三、连接百度服务器
尝试连接到百度服务器
// 4、使用socket()函数获取一个TCP客户端socket文件描述符
int tcp_client = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == tcp_client)
{
perror("socket");
return ;
}
// 5、链接到服务器
err = connect(tcp_client, (const struct sockaddr *)ipv4, sizeof(*ipv4));
if (err < 0)
perror("connect err");
else
printf("connect success, ret = %d.\n", err);
编译,烧录,可以看到,连接成功
我们尝试发送一个GET请求,
// 6. 发送GET请求
char sendbuf[]={"GET / HTTP/1.1\n\n"};
err = send(tcp_client, sendbuf, strlen(sendbuf),0);
if (err < 0)
perror("send err");
else
printf("send size %d \n",err);
// 7、等待接收服务端发送过来的数据,最大接收100个字节
char recvbuf[100] = {0};
err = recv(tcp_client, recvbuf, sizeof(recvbuf), 0);
if (err < 0)
perror("recv err");
else
printf("recv size %d \n",err);
// 8、将接收到的数据打印出来
printf("Recvdate: \n%s \n",recvbuf);
// 9、关闭套接字
close(tcp_client);
可以看到,请求成功
五、代码
最后贴上app_main.c完整代码
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "driver/gpio.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#define GPIO_LED_NUM 2 /* LED引脚编号 */
/* wifi连接函数,位于app_wifi.c,阻塞状态 */
void wifi_connect_init(void);
#define HOST_IP_ADDR "192.168.0.102"
static void dns_client_task(void *pvParameters)
{
// 1、定义一个hints结构体,用来设置函数的getaddrinfo()的使用方式
const struct addrinfo hints = {
.ai_family = AF_INET, /* 指定返回地址的协议簇,AF_INET(IPv4)、AF_INET6(IPv6)、AF_UNSPEC(IPv4 and IPv6)*/
.ai_socktype = SOCK_STREAM, /* 设定返回地址的socket类型,流式套接字 */
};
// 2、使用getaddrinfo()开始解析,定义一个struct addrinfo结构体指针,用来获取解析结果
struct addrinfo *result;
int err;
err = getaddrinfo("www.baidu.com", "80", &hints, &result);
if(err != 0) /* 返回值不为0,函数执行失败*/
printf("getaddrinfo err: %d \n",err);
// 3、将获取到的信息打印出来
char buf[100]; /* 用来存储IP地址字符串 */
struct sockaddr_in *ipv4 = NULL; /* IPv4地址结构体指针 */
if(result->ai_family == AF_INET)
{
ipv4 = (struct sockaddr_in *)result->ai_addr;
inet_ntop(result->ai_family, &ipv4->sin_addr, buf, sizeof(buf));
printf("[IPv4]%s [port]%d \n",buf,ntohs(ipv4->sin_port));
}
else
printf("got IPv4 err !!!\n");
// 4、使用socket()函数获取一个TCP客户端socket文件描述符
int tcp_client = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == tcp_client)
{
perror("socket");
return ;
}
// 5、链接到服务器
err = connect(tcp_client, (const struct sockaddr *)ipv4, sizeof(*ipv4));
if (err < 0)
perror("connect err");
else
printf("connect success, ret = %d.\n", err);
// 6. 发送GET请求
char sendbuf[]={"GET / HTTP/1.1\n\n"};
err = send(tcp_client, sendbuf, strlen(sendbuf),0);
if (err < 0)
perror("send err");
else
printf("send size %d \n",err);
// 7、等待接收服务端发送过来的数据,最大接收100个字节
char recvbuf[100] = {0};
err = recv(tcp_client, recvbuf, sizeof(recvbuf), 0);
if (err < 0)
perror("recv err");
else
printf("recv size %d \n",err);
// 8、将接收到的数据打印出来
printf("Recvdate: \n%s \n",recvbuf);
// 9、关闭套接字
close(tcp_client);
// 10、释放addrinfo 内存
freeaddrinfo(result);
vTaskDelete(NULL);
}
void app_main(void)
{
/* 打印Hello world! */
printf("Hello world!\n");
wifi_connect_init();
xTaskCreate(dns_client_task, "tcp_client", 4096, NULL, 5, NULL);
while(1)
{
gpio_set_level(GPIO_LED_NUM, 0); /* 熄灭 */
vTaskDelay(500 / portTICK_PERIOD_MS); /* 延时500ms*/
gpio_set_level(GPIO_LED_NUM, 1); /* 点亮 */
vTaskDelay(500 / portTICK_PERIOD_MS); /* 延时500ms*/
}
}
更多推荐
所有评论(0)