其他分享
首页 > 其他分享> > ESP32 之 ESP-IDF 教学WiFi篇(二)—— LwIP 之 TCP 通信

ESP32 之 ESP-IDF 教学WiFi篇(二)—— LwIP 之 TCP 通信

作者:互联网

本文章 来自原创专栏《ESP32教学专栏 (基于ESP-IDF)》 下的一个二级专栏 《ESP32 上的 WiFi 及 Lwip 协议栈》,讲解如何使用 ESP-IDF 构建 ESP32 程序,发布文章并会持续为已发布文章添加新内容! 每篇文章都经过了精打细磨!

↓↓↓通过下方链接进入专栏主页↓↓↓


文章目录

一、建立连接 —— ESP32 作 TCP Client客户端

1. TCP Client 的基本思路

在这里插入图片描述

2. TCP Client 代码示例

以下代码是一个函数tcp_task_client实现的是一个FreeRTOS的Task,在这个任务里完成了以下内容:

具体请见注释

void tcp_task_client(void *arg){
    xEventGroupWaitBits(wifiEvent, wifiConnectedBit, pdFALSE, pdFALSE, portMAX_DELAY);
    int _socket;

createSocket:	// 标签

    _socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    // AF_INET表示IPv4,AF_INET6表示IPv6

    // SOCK_STREAM表示TCP;
    // SOCK_DGRAM表示UDP;
    // SOCK_RAW表示RAW

    // protocol, 规定套接字发送和接送哪类型协议数据。
    // 最常见的是 IPPROTO_TCP, IPPROTO_UDP, IPPROTO_UDPLITE、IPPROTO_ICMP。
    // 如果 domain 和 type已经确定唯一的协议,“0(IPPROTO_IP)” 可以用来表示选择一个默认的协议。

    if(_socket < 0){
        printf("Socket 创建失败, 错误代码:%d\n", errno);
        vTaskDelete(NULL);
    }else{
        printf("Socket 创建成功");
    }

    struct sockaddr_in desk_addr = {
    // 下边这个IP 192.168.31.138和端口号8080是自己设置的,请按需要修改
        .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; // goto标签
            
        }
    }
    vTaskDelete(NULL);
}

二、建立连接 —— ESP32 做 TCP Server服务器

1. 代码示例

以下代码是一个函数tcp_task_server实现的是一个FreeRTOS的Task,在这个任务里完成了以下内容:

具体请见注释

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);
        //xTaskNotifyGive(tcp_client_handle);

        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)则根据前两个参数自动选择协议

标签:LwIP,socket,ESP,int,ESP32,TCP,IPPROTO,addr
来源: https://blog.csdn.net/m0_50064262/article/details/120265731