Chapter 16 TCP Connection of ESP32

Pay attention to the public account of Jiayouchuang Technology

 

Learning goals and objectives

  • Master the principle and working process of TCP
  • Master the programming of the TCP of Espressif ESP32
  • Mainly master the detailed process of TCP as Client

TCP science (from Baidu Encyclopedia)

TCP (Transmission Control Protocol  ) is a connection-oriented, reliable , byte stream-based transport layer communication protocol, defined by IETF's RFC 793. In the simplified OSI model of computer network, it completes the functions specified by the fourth layer transport layer, the User Datagram Protocol (UDP) is the same layer, another important transport protocol. In the Internet protocol suite, the TCP layer is an intermediate layer above the IP layer and below the application layer. Reliable, pipe-like connections are often required between application layers of different hosts, but the IP layer does not provide such a streaming mechanism, but provides unreliable packet exchange.

The application layer sends a data stream represented by 8-bit bytes for Internet transmission to the TCP layer, and then TCP partitions the data stream into segments of appropriate length (usually controlled by the data link layer of the network to which the computer is connected). Maximum Transmission Unit (MTU) limit). Then TCP passes the result packet to the IP layer, which transmits the packet through the network to the TCP layer of the receiving entity. In order to ensure that no packet loss occurs, TCP gives each packet a sequence number, and the sequence number also ensures the orderly reception of packets transmitted to the receiving entity. The receiver entity then sends back a corresponding acknowledgment (ACK) for the successfully received packet; if the sender entity does not receive an acknowledgment within a reasonable round-trip delay ( RTT ), then the corresponding packet is assumed to have been Losses will be retransmitted. TCP uses a checksum function to check data for errors; checksums are calculated both when sending and receiving.

connection establishment

TCP is the transport layer protocol in the Internet and uses a three-way handshake protocol to establish connections. When the active party sends a SYN connection request, wait for the other party to answer SYN+ACK, and finally perform ACK confirmation on the other party's SYN. This method of establishing a connection prevents false connections, and the flow control protocol used by TCP is a variable-size sliding window protocol.

The process of the TCP three-way handshake is as follows:

  • The client sends a SYN (SEQ=x) message to the server and enters the SYN_SEND state.
  • The server receives the SYN message, responds with a SYN (SEQ=y) ACK (ACK=x+1) message, and enters the SYN_RECV state.
  • The client receives the SYN message from the server, responds with an ACK (ACK=y+1) message, and enters the Established state.
      1. connection terminated

Terminating a connection requires a four-way handshake, which is caused by TCP's half-close. The specific process is shown in the figure below. [1] 

  • An application process first calls close, which is called an "active close". The TCP on this end then sends a FIN segment, indicating that the data is sent.
  • The peer that receives this FIN performs a "passive close", and the FIN is acknowledged by TCP.
  • After a period of time, the application process that receives this end-of-file will call close to close its socket. This causes its TCP to also send a FIN.
  • The original sender TCP that received the final FIN (that is, the end that performed the active shutdown) confirms the FIN

TCP features and processes

The above principles are very important, but after all, we are only doing applications on top of the API. Just need to understand the features and processes . Knowing the characteristics, you can consider the feasibility when making a plan, and the process is the implementation after it is feasible.

TCP features:

  • Connection-oriented: A connection must be made before sending data.
  • Reliable connection: The data transmitted by the TCP connection is error-free, not lost, not duplicated, and arrives in sequence.
  • Point-to-point: The data transmitted by the TCP connection is error-free, not lost, not repeated, and arrives in sequence
  • Maximum length is limited: only 1500 bytes. ( http and websocket come into play )

TCP process: ( source of this paragraph )

The general steps of the client side of TCP programming are:

  • Create a socket, use the function socket(); 
  • To set socket properties, use the function setsockopt(); (optional)
  • Bind IP address, port and other information to the socket, use the function bind();* optional 
  • Set properties such as the IP address and port of the other party to be connected; 
  • To connect to the server, use the function connect(); 
  • To send and receive data, use the functions send() and recv(), or read() and write(); 
  • close the network connection;

The general steps on the server side of TCP programming are: 

  1. Create a socket, use the function socket();
  2. To set the socket property, use the function setsockopt(); (optional) 
  3. Bind IP address, port and other information to the socket, use the function bind();
  4. To enable monitoring, use the function listen();
  5. To receive the connection from the client, use the function accept();
  6. To send and receive data, use the functions send() and recv(), or read() and write(); 
  7. Close the network connection; closesocket();
  8. close monitoring; 

TCP and UDP (in the next chapter) fight each other

 

software design

The main logic of ESP32 's TCP Client (similar to Server)

 

Detailed process logic of new task and receiving task of TCP Client

 

 

Introduction to the TCP interface of ESP32

ESP32 uses LwIP. LwIP is a small open source TCP/IP protocol stack especially suitable for embedded devices, which occupies very little memory resources. ESP-IDF is a transplant of the LwIP protocol stack. Learn to understand LwIP, and recommend this book to everyone, "Things on Embedded Networks: In-depth Analysis and Practical Drills of LwIP Protocol".

Our routine directly uses the standard socket interface (internally encapsulated by LwIP), and does not use LwIP. The interface explanation about LwIP is explained in Websocket, and the usage is the same. After knowing the process, the API call can be used. Handle exceptions well. Process + interface, invincible. For the tutorial of LwIP, please refer to the documentation of Avnet and Wildfire.

The following macro definitions can be seen in the src/include/lwip/socket.h file. The socket of lwip also provides standard socket interface functions.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

#if LWIP_COMPAT_SOCKETS

#define accept(a,b,c)         lwip_accept(a,b,c)

#define bind(a,b,c)           lwip_bind(a,b,c)

#define shutdown(a,b)         lwip_shutdown(a,b)

#define closesocket(s)        lwip_close(s)

#define connect(a,b,c)        lwip_connect(a,b,c)

#define getsockname(a,b,c)    lwip_getsockname(a,b,c)

#define getpeername(a,b,c)    lwip_getpeername(a,b,c)

#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e)

#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e)

#define listen(a,b)           lwip_listen(a,b)

#define recv(a,b,c,d)         lwip_recv(a,b,c,d)

#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f)

#define send(a,b,c,d)         lwip_send(a,b,c,d)

#define sendto(a,b,c,d,e,f)   lwip_sendto(a,b,c,d,e,f)

#define socket(a,b,c)         lwip_socket(a,b,c)

#define select(a,b,c,d,e)     lwip_select(a,b,c,d,e)

#define ioctlsocket(a,b,c)    lwip_ioctl(a,b,c)

 

#if LWIP_POSIX_SOCKETS_IO_NAMES

#define read(a,b,c)           lwip_read(a,b,c)

#define write(a,b,c)          lwip_write(a,b,c)

#define close(s)              lwip_close(s)

  • New socket function: socket();
  • Connection function: connect();
  • Close the socket function: close();
  • Get socket error code: getsocketopt();
  • Receive data function: recv();
  • Send data function: send();
  • Binding function: bing();
  • Listener function: listen();
  • Get the connection function: accept();

For more detailed interfaces, please refer to the official guide .

 

Summary of TCP for ESP32

After initializing the wifi configuration, the program will return the status in the callback function according to the real-time status of the WIFI, so you only need to perform related operations in the callback, the STA start event triggers the TCP connection, and the data can be exchanged after the connection. Among them, it is extremely important to deal with abnormal conditions of the connection. TCP is reliable and cannot be used as a commodity.

 

 

Writing a new TCP task

Only talk about Client, server look at the source code .

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

esp_err_t create_tcp_client()

{undefined

    ESP_LOGI(TAG, "will connect gateway ssid : %s port:%d",

             TCP_SERVER_ADRESS, TCP_PORT);

    // create a new socket

    connect_socket = socket (AF_INET, SOCK_STREAM, 0);

    if (connect_socket < 0)

    {undefined

        //print error message

        show_socket_error_reason("create client", connect_socket);

        //After the new creation fails, close the newly created socket and wait for the next new creation

        close(connect_socket);

        return ESP_FAIL;

    }

    //Configure connection server information: port + ip

    server_addr.sin_family = AF_INET;

    server_addr.sin_port = htons(TCP_PORT);

    server_addr.sin_addr.s_addr = inet_addr(TCP_SERVER_ADRESS);

    ESP_LOGI(TAG, "connectting server...");

    //connect to the server

    if (connect(connect_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)

    {undefined

        //print error message

        show_socket_error_reason("client connect", connect_socket);

        ESP_LOGE(TAG, "connect failed!");

        //After the connection fails, close the previously created socket and wait for the next new one

        close(connect_socket);

        return ESP_FAIL;

    }

    ESP_LOGI(TAG, "connect success!");

    return ESP_OK;

}

 

 

TCP receive task code

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

void recv_data(void *pvParameters)

{undefined

    int len ​​= 0; //length

    char databuff[1024]; //cache

    while (1)

    {undefined

        //Empty the cache

        memset(databuff, 0x00, sizeof(databuff));

        //read received data

        len = recv(connect_socket, databuff, sizeof(databuff), 0);

// exception flag

        g_rxtx_need_restart = false;

        if (len > 0)

        {undefined

            // print the received array

            ESP_LOGI(TAG, "recvData: %s", databuff);

            //Receive data back

            send(connect_socket, databuff, strlen(databuff), 0);

        }

        else

        {undefined

            // print error message

            show_socket_error_reason("recv_data", connect_socket);

            //Server failure, mark reconnection

            g_rxtx_need_restart = true;

     

            break;

        }

    }

    close_socket();

    // mark reconnection

    g_rxtx_need_restart = true;

    vTaskDelete (NULL);

}

 

 

TCP exception handling

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

static void tcp_connect(void *pvParameters)

{undefined

    . . . . . . .

        while (1)

        {undefined

            vTaskDelay(3000 / portTICK_RATE_MS);

            //Re-create the client, the same as creating a new one

            if (g_rxtx_need_restart)

            {undefined

                vTaskDelay(3000 / portTICK_RATE_MS);

                ESP_LOGI(TAG, "reStart create tcp client...");

                //create client

                int socket_ret = create_tcp_client();

                if (socket_ret == ESP_FAIL)

                {undefined

                    ESP_LOGE(TAG, "reStart create tcp socket error,stop...");

                    continue;

                }

                else

                {undefined

                    ESP_LOGI(TAG, "reStart create tcp socket succeed...");

                    //Rebuild is complete, clear the flag

                    g_rxtx_need_restart = false;

                    //Create a tcp receive data task

                    xTaskCreate(&recv_data, "recv_data", 4096, NULL, 4, &tx_rx_task);

                }

            }

    }

    vTaskDelete (NULL);

}

    return ESP_OK;

}

 

Test process and effect display

test process

  • Client test
  1. Change the account password of AP and STA
  2. #define TCP_SERVER_CLIENT_OPTION FALSE //esp32 as client
  3. Modify the IP (computer/mobile phone) and Port that connect to the server as a client
  4. Use a mobile phone or computer to use the assistant tool to establish a server, and let esp32 connect automatically
  • Server test
  1. #define TCP_SERVER_CLIENT_OPTION TRUE //esp32 as server
  2. Modify the Port listened to when serving as a Server
  3. Mobile phone or computer directly connected to the AP of ESP32
  4. Use the TCP assistant tool as the Client to connect to the esp32 server
      1. Show results

Client effect display

Build the server first and wait for the ESP32 to come and connect.

test send data

pressure test

Server effect display

AP connected to ESP32

test send data

pressure test

test exception

 

Summary of TCP

  • The bottom layer emphasizes the principle, and the application emphasizes the process + interface.
  • The small pressure test does not lose packets, and the product stability should be measured in a large scale when transplanting by yourself.
  • Source address: https://github.com/xiaolongba/wireless-tech

Click me -> more ESP32 development guide series catalog

Related: Chapter 16 TCP Connection of ESP32