ESP32 with TCP/IP protocol
ESP32 with TCP/IP protocol

A TCP (transmission control protocol) is a connection-oriented communication. It is an intermediate layer of the application layer and internet protocol layer in OSI model. TCP is designed to send the data packets over the network. It ensures that data is delivered to the correct destination. TCP creates a connection between the source and destination node before transmitting the data and keep the connection alive until the communication is active.

The communication over the network in TCP/IP model takes place in form of a client-server architecture. ie, the client begins the communication and establish a connection with a server. For more understanding lets create a server which continuously runs and establish the connection after getting a request from the client.

TCP/IP Server-Client Model

Flow diagram
  1. Socket : Create a new communication endpoint.
  2. Bind : Attach an ip or local address to the socket.
  3. Listen : Announce a willingness to accept connections.
  4. Accept : Block caller until connection request arrives.
  5. Connect: Actively attempt to establish a connection.
  6. Send : Send some data over the connection.
  7. Read : Receive some data over the connection.
  8. Close : Release the connection.

In this example, ESP32 is configured as server and linux pc as client. After the connection with a client, the server will wait for a message from the client. After getting the message server will check the received message then turn on the led connected to the gpio and send a proper response as per the received message.

ESP32 as a server

static void tcpServer(void *pvParameters)
{
        int addr_family = AF_INET;
        int ip_protocol = 0;
        struct sockaddr_in dest_addr;

        struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;
        dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);
        dest_addr_ip4->sin_family = AF_INET;
        dest_addr_ip4->sin_port = htons(PORT);
        ip_protocol = IPPROTO_IP;

        //Create a socket
        int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);
        if (listen_sock < 0) {
                ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
                vTaskDelete(NULL);
                return;
        }
        int opt = 1;
        setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

        ESP_LOGI(TAG, "Socket created");

        //Bind the socket to an address
        int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
        if (err != 0) {
                ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
                goto CLEAN_UP;
        }
        ESP_LOGI(TAG, "Socket bound, port %d", PORT);

        //Listen for connections
        err = listen(listen_sock, 1);
        if (err != 0) {
                ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
                goto CLEAN_UP;
        }
        ESP_LOGI(TAG, "Socket listening");

        struct sockaddr_in source_addr;
        uint addr_len = sizeof(source_addr);
        //Accept a connection, This call typically blocks until a client connects with the server.
        int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
        if (sock < 0) {
                ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
                return;
        }

        while (1) {

                //Send and receive data
........................

In app_main function the gpio is initialized for led control. GPIO 32 is connected to led which will be controlled by tcp client.

For configuring wifi as station mode and to connect with a access point please use idf.py menuconfig —> example configuration. Specify your access point ssid and password. After successful building and flashing the firmware. Then after running the firmware, ESP32 will connects with specified access point and gets its own ip address which will be displayed on console.

Linux as tcp client.

#define PORT 3333 
#define SERVERIP        "192.168.1.5"

int main(int argc, char const *argv[])
{
        int sock = 0;
        struct sockaddr_in serv_addr;

        char cmd,option;
        char buffer[1024] = {0};
        //Create a socket
        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
                printf("\n Socket creation error \n");
                return -1;
        }

        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(PORT);

        // Convert IPv4 addresses from text to binary form 
        if(inet_pton(AF_INET,SERVERIP, &serv_addr.sin_addr)<=0)
        {
                printf("\nInvalid address/ Address not supported \n");
                return -1;
        }
        //Establish a connection with a TCP server
        if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
        {
                printf("\nConnection Failed \n");
                return -1;
        }

        do
        {
                //Send and receive data
                printf("\nEnter 1 - on or 0 - off = ");
                scanf("%c",&cmd);
                send(sock , &cmd , 1 , 0 );
                read( sock , buffer, 1024);
                printf("%s\n",buffer );
                printf("Do you want to continue = ");
                scanf("\n%c",&option);
                getchar();
        }while(option == 'y' || option == 'Y');
        close(sock);
        return 0;
}

After the configuration the server will get its own ip address which will be displayed on console. Use the same address for client.c SERVERIP macro. Then compile the client.c file by gcc client.c -o client in command line.
To run the client program ./client, use 1 or 0 to turn on or off the led which is connected to the server.

The ESP32 project and client.c file is provided in github