Skip to content

Concepts First ​

  • TCP server: a device that listens on a port and waits for clients to connect; once connected, both sides can exchange data.
  • listen: after socket() and bind(), the server calls listen() to start listening and accept() to take incoming connections.
  • Echo: the example returns received data verbatim to verify bidirectional transfer.
  • Point-to-point connections: a TCP server can accept clients one after another, but each connection is independent and has its own socket.

Example Overview ​

This page covers the TCP server (echo) part of the wifi_tcp example in the official Bouffalo SDK (examples/wifi/sta/wifi_tcp/wifi_tcp_server.c):

  • standard lwIP server flow: socket → bind → listen → accept;
  • prints the received length and writes the data back (echo), processed every 500ms;
  • setsockopt(TCP_NODELAY) disables Nagle's algorithm to reduce small-packet latency;
  • the shell command wifi_tcp_echo_test <port> starts the server; Ctrl+C exits and prints transfer statistics.
  • Sibling example: wifi_tcp_client.c in the same directory provides the client command wifi_tcp_test <ip> <port> (see TCP Client).

Operation Steps ​

1
Enter the Example Directory

Open a terminal and enter the SDK TCP example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):

cd examples/wifi/sta/wifi_tcp
2
Build the Project

Both Ai-M61 and Ai-M62 use bl616:

make CHIP=bl616 BOARD=bl616dk
3
Flash the Firmware

Hold BOOT (IO2 on the Ai-M61-32S-Kit), briefly press EN/RST to enter download mode, then flash:

make flash CHIP=bl616 COMX=/dev/ttyUSB0
4
Connect Wi-Fi and Start the Server

Serial tool at 2000000 baud. Wait for bouffalolab />, connect to the router, then start the TCP server listening on port 3365:

wifi_sta_connect Your_SSID 12345678
wifi_tcp_echo_test 3365
5
Run and Verify

On the PC, connect to the module’s IP (port 3365) with netcat; anything you type is echoed back verbatim:

nc -v 192.168.1.3 3365

Code Execution Flow ​

The complete server flow from boot to echo:

APIs Used by the Example ​

socket(AF_INET, SOCK_STREAM, 0) ​

Creates a TCP socket; the handle is used by bind/listen/accept.

Parameters:

  • AF_INET: IPv4 family
  • SOCK_STREAM: stream (TCP) socket

Return: >= 0 handle; < 0 on failure

bind(sock, addr, len) ​

Binds the socket to a local address and port — required before a server can be reached.

Parameters:

  • sock: socket handle
  • addr: sockaddr_in with htons(port) and INADDR_ANY

Return: 0 on success; -1 on failure

listen / accept(sock, backlog) / (sock, addr, len) ​

listen() enters listening state (backlog = queue length, 5 in the example); accept() blocks until a client connects and returns a new connection socket.

Parameters:

  • sock: listening socket

Return: accept returns the new connection handle; -1 on failure

recv / write(sock, buf, len, 0) ​

recv() reads data (returns byte count; <= 0 means closed/error); write() sends data.

Parameters:

  • sock: accepted connection socket
  • buf / len: buffer and length

Return: bytes transferred; <= 0 on error/close

setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, ...) ​

Disables Nagle's algorithm so each write is sent immediately — good for interactive small packets.

Parameters:

  • sock: connection socket
  • TCP_NODELAY: option, flag = 1

Return: 0 on success; -1 on failure

Complete Code ​

The full wifi_tcp example sources related to the TCP server, identical to the official example (examples/wifi/sta/wifi_tcp). Collapsed by default; click to expand:

📜 Click to expand wifi_tcp/main.c full code
c
/****************************************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"

#include <lwip/tcpip.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>

#include "wifi_mgmr_ext.h"
#ifndef BL602
#include "fhost_api.h"
#include "wifi_mgmr.h"
#endif

#include "bflb_irq.h"
#include "bflb_uart.h"

#include "rfparam_adapter.h"
#include "async_event.h"
#include "mm.h"
#include "board.h"
#include "shell.h"

#define DBG_TAG "MAIN"
#include "log.h"

struct bflb_device_s *gpio;

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/****************************************************************************
 * Private Types
 ****************************************************************************/

/****************************************************************************
 * Private Data
 ****************************************************************************/

static struct bflb_device_s *uart0;

extern void shell_init_with_task(struct bflb_device_s *shell);
extern void wifi_event_handler(async_input_event_t ev, void *priv);
#ifdef BL602
extern void wifi_task_create(void);
extern int fhost_init(void);
extern int wifi_mgmr_task_start(void);
#endif

/****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/

/****************************************************************************
 * Functions
 ****************************************************************************/

void wifi_start_firmware_task(void *param)
{
    LOG_I("Starting wifi ...\r\n");

    async_register_event_filter(EV_WIFI, wifi_event_handler, NULL);

    wifi_task_create();

    LOG_I("Starting fhost ...\r\n");
#ifndef BL602
    fhost_init();
#endif

    vTaskDelete(NULL);
}

void wifi_event_handler(async_input_event_t ev, void *priv)
{
    uint32_t code = ev->code;

    switch (code) {
        case CODE_WIFI_ON_INIT_DONE: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_INIT_DONE\r\n", __func__);
            wifi_mgmr_task_start();
        } break;
        case CODE_WIFI_ON_MGMR_DONE: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_MGMR_DONE\r\n", __func__);
        } break;
        case CODE_WIFI_ON_SCAN_DONE: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_SCAN_DONE\r\n", __func__);
            wifi_mgmr_sta_scanlist();
        } break;
        case CODE_WIFI_ON_CONNECTED: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_CONNECTED\r\n", __func__);
            void mm_sec_keydump();
            mm_sec_keydump();
        } break;
        case CODE_WIFI_ON_GOT_IP: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP\r\n", __func__);
            LOG_I("[SYS] Memory left is %d Bytes\r\n", kfree_size(0));
        } break;
        case CODE_WIFI_ON_DISCONNECT: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_DISCONNECT\r\n", __func__);
        } break;
        case CODE_WIFI_ON_AP_STARTED: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STARTED\r\n", __func__);
        } break;
        case CODE_WIFI_ON_AP_STOPPED: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STOPPED\r\n", __func__);
        } break;
        case CODE_WIFI_ON_AP_STA_ADD: {
            LOG_I("[APP] [EVT] [AP] [ADD] %lld\r\n", xTaskGetTickCount());
        } break;
        case CODE_WIFI_ON_AP_STA_DEL: {
            LOG_I("[APP] [EVT] [AP] [DEL] %lld\r\n", xTaskGetTickCount());
        } break;
        default: {
            LOG_I("[APP] [EVT] Unknown code %u \r\n", code);
        }
    }
}

int main(void)
{
    board_init();

    uart0 = bflb_device_get_by_name("uart0");
    shell_init_with_task(uart0);

    if (0 != rfparam_init(0, NULL, 0)) {
        LOG_I("PHY RF init failed!\r\n");
        return 0;
    }

    LOG_I("PHY RF init success!\r\n");

    tcpip_init(NULL, NULL);

    xTaskCreate(wifi_start_firmware_task, "wifi init", 1024, NULL, 10, NULL);

    vTaskStartScheduler();

    while (1) {
    }
}
📜 Click to expand wifi_tcp_server.c full code
c


#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <lwip/api.h>
#include <lwip/arch.h>
#include <lwip/opt.h>
#include <lwip/inet.h>
#include <lwip/errno.h>
#include <netdb.h>

#include "shell.h"
#include "utils_getopt.h"
#include "bflb_mtimer.h"

// clang-format off
// clang-format on

#define RECV_DATA_LEN (1024)
#define PING_USAGE                  \
    "wifi_tcp_echo_test [port]\r\n" \
    "\t port: local server listen port\r\n"

shell_sig_func_ptr abort_exec;
uint64_t recv_data_cnt = 0;
int sock_server = -1, connected;
char *recv_data;

static void test_close(int sig)
{
    if (connected >= 0) {
        closesocket(connected);
        connected = -1;
    }
    if (sock_server >= 0) {
        closesocket(sock_server);
    }
    if (recv_data) {
        free(recv_data);
        recv_data = NULL;
    }
    abort_exec(sig);
    if (recv_data_cnt > 0) {
        printf("recv data=%lld\r\n", recv_data_cnt);
    }
}

static void wifi_test_tcp_server_init(int argc, char **argv)
{
    abort_exec = shell_signal(SHELL_SIGINT, test_close);
    printf("tcp server task start ...\r\n");

    char *port;
    struct sockaddr_in server_addr, client_addr;
    socklen_t sin_size;

    if (argc < 2) {
        printf("%s", PING_USAGE);
        return;
    }

    /* get listen port (argv[1] if present) */
    port = argv[1];

    recv_data = (char *)pvPortMalloc(RECV_DATA_LEN);
    if (recv_data == NULL) {
        printf("not memory\r\n");
        return;
    }
    /* create socket */
    if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("TCP server create socket error\r\n");
        return;
    }
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(port));
    server_addr.sin_addr.s_addr = INADDR_ANY;
    memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));

    /* bind socket */
    if (bind(sock_server, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
        printf("TCP server socket bind fail!\r\n");
        return;
    }

    /* listen port */
    if (listen(sock_server, 5) == -1) {
        printf("TCP server listen error!\r\n ");
        return;
    }

    printf("TCP Server listen start: localhost:%s\r\n", port);
    printf("please connet ...\r\n");

    while (1) {
        sin_size = sizeof(struct sockaddr_in);
        connected = accept(sock_server, (struct sockaddr *)&client_addr, &sin_size);
        printf("new client connected from (%s, %d)\r\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

        int flag = 1;
        setsockopt(connected, IPPROTO_TCP, TCP_NODELAY, (void *)&flag, sizeof(int));

        printf("Press CTRL-C to exit.\r\n");
        recv_data_cnt = 0;
        while (1) {
            recv_data_cnt = recv(connected, recv_data, RECV_DATA_LEN, 0);
            if (recv_data_cnt <= 0) {
                break;
            }
            printf("recv %lld len data\r\n", recv_data_cnt);
            if (write(connected, recv_data, recv_data_cnt) < 0) {
                printf("write falied!\r\n");
                break;
            }
            vTaskDelay(500);
        }
        if (connected >= 0) {
            closesocket(connected);
            connected = -1;
        }
        if (sock_server >= 0) {
            closesocket(sock_server);
        }
        if (recv_data) {
            free(recv_data);
            recv_data = NULL;
        }

        return;
    }
}

#ifdef CONFIG_SHELL
#include <shell.h>

int cmd_wifi_tcp_server(int argc, char **argv)
{
    wifi_test_tcp_server_init(argc, argv);

    return 0;
}

SHELL_CMD_EXPORT_ALIAS(cmd_wifi_tcp_server, wifi_tcp_echo_test, wifi tcp test);
#endif

FAQ ​

The PC cannot connect to the module's port

Confirm the module and PC are on the same router/subnet (find the module's IP via CODE_WIFI_ON_GOT_IP or the ifconfig command); use wifi_tcp_echo_test 3365 (not the client command); disable AP isolation if the router has it.

Connected but no echo

Check the nc address is the module's IP; the example handles one client at a time and exits after that connection ends — rerun the command to listen again.

Have questions?

For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

Released under the MIT License. Build Time 2026-09-30 17:31:25