本文章 来自原创专栏《ESP32教学专栏 (基于ESP-IDF)》,讲解如何使用 ESP-IDF 构建 ESP32 程序,发布文章并会持续为已发布文章添加新内容! 每篇文章都经过了精打细磨!
↓↓↓通过下方对话框进入专栏目录页↓↓↓
CSDN 请求进入目录 _ O x
是否进入ESP32教学导航(基于ESP-IDF)?
确定
文章目录
- 一、建立连接 —— ESP32 作 TCP Client客户端
- 1. TCP Client 的基本思路
- 2. TCP Client 代码示例
- 二、建立连接 —— ESP32 做 TCP Server服务器
-
- 三、收发数据
- 四、LwIP BSD API 与TCP/UDP 有关的函数
一、建立连接 —— ESP32 作 TCP Client客户端
1. TCP Client 的基本思路
2. TCP Client 代码示例
以下代码是一个函数tcp_task_client
实现的是一个FreeRTOS的Task,在这个任务里完成了以下内容:
- 等待WiFi连接成功(基于FreeRTOS API 之 事件组
Event Group
) - 创建Socket对象并初始为TCP(注意代码第7行),并检测Socket是否创建成功。
- 配置连接参数结构(结构体
struct sockaddr_in
类型的desk_addr
) - 循环连接服务端,直至连接成功
具体请见注释
void tcp_task_client(void *arg){
xEventGroupWaitBits(wifiEvent, wifiConnectedBit, pdFALSE, pdFALSE, portMAX_DELAY);
int _socket;
createSocket:
_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if(_socket < 0){
printf("Socket 创建失败, 错误代码:%d\n", errno);
vTaskDelete(NULL);
}else{
printf("Socket 创建成功");
}
struct sockaddr_in desk_addr = {
.sin_addr.s_addr = inet_addr("192.168.31.138"),
.sin_family = AF_INET,
.sin_port = htons(8080),
};
int err;
while (1) {
err = connect(_socket, (struct sockaddr*)&desk_addr, sizeof(desk_addr));
if (err == 0){
ESP_LOGI("CLIENT", "连接成功");
break;
}else{
ESP_LOGI("CLIENT", "连接失败,错误代码:%d", errno);
close(_socket);
vTaskDelay(pdMS_TO_TICKS(200));
goto createSocket;
}
}
vTaskDelete(NULL);
}
二、建立连接 —— ESP32 做 TCP Server服务器
1. 代码示例
以下代码是一个函数tcp_task_server
实现的是一个FreeRTOS的Task,在这个任务里完成了以下内容:
- 等待WiFi连接成功(基于FreeRTOS API 之 事件组
Event Group
) - 创建Socket对象并初始为TCP(注意代码第7行),并检测Socket是否创建成功。
- 配置连接参数结构(结构体
struct sockaddr_in
类型的desk_addr
) - 绑定
- 开始监听
- 执行accept函数,从已建立TCP连接的客户端Sockets中去除Socket(此函数会阻塞,因此请按需使其出现在恰当的位置)
具体请见注释
void tcp_task_server(void *arg){
xEventGroupWaitBits(wifiEvent, wifiConnectedBit, pdFALSE, pdFALSE, portMAX_DELAY);
int _socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if(_socket < 0){
printf("Socket 创建失败, 错误代码:%d\n", errno);
vTaskDelete(NULL);
}else{
printf("Socket 创建成功");
}
struct sockaddr_in desk_addr = {
.sin_addr.s_addr = INADDR_ANY,
.sin_family = AF_INET,
.sin_port = htons(2501),
};
int err;
while(1){
err = bind(_socket, (struct sockaddr*)&desk_addr, sizeof(desk_addr));
if(err == 0){
ESP_LOGI("SERVICE", "绑定成功");
break;
}else{
ESP_LOGI("SERVICE", "绑定失败, 错误代码: %d", errno);
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
err = listen(_socket, 5);
if (err != 0){
ESP_LOGI("SERVICE", "监听失败,错误代码: %d", errno);
vTaskDelete(NULL);
}else{
ESP_LOGI("SERVICE", "监听成功");
}
while (1){
struct sockaddr_in6 source_addr;
uint addr_len;
ESP_LOGI("SERVICE", "准备accept");
int remote_sock = accept(_socket, (struct sockaddr *) &source_addr, &addr_len);
if(remote_sock < 0){
ESP_LOGI("SERVICE", "accept失败,错误代码: %d", errno);
}else{
ESP_LOGI("SERVICE", "连接成功");
break;
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
vTaskDelete(NULL);
}
三、收发数据
四、LwIP BSD API 与TCP/UDP 有关的函数
socket()
bind()
listen()
connect()
accept()
send(), recv(), sendto(), recvfrom()
close()
gethostbyname()
select()
pool()
getsockopt(), setsockopt()
函数名 | socket() |
---|
函数原型 | int socket(int domain, int type, int protocol) |
含义 | 函数socket()为通信创建一个端点,并为该套接字返回一个文件描述符。 |
返回值 | int,若发生错误则返回-1 |
参数 | domain类型为:int ;表示欲创建的协议族。 如:AF_INET 表示IPv4,
AF_INET6 表示IPv6,
AF_UNIX 表示本地套接字
type类型为:int ; 如:SOCK_STREAM 表示TCP,
SOCK_DGRAM 表示UDP,
SOCK_SEQPACKET 表示可靠的顺序包服务,
SOCK_RAW 表示网络层上的原始协议
protocol类型为:int ;表示指定要使用的实际传输协议。最常见的有IPPROTO_TCP , IPPROTO_SCTP , IPPROTO_UDP , IPPROTO_DCCP 等。如果填0(IPPRORO_IP)则根据前两个参数自动选择协议 |
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)