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()andbind(), the server callslisten()to start listening andaccept()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+Cexits and prints transfer statistics. - Sibling example:
wifi_tcp_client.cin the same directory provides the client commandwifi_tcp_test <ip> <port>(see TCP Client).
Operation Steps
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_tcpBoth Ai-M61 and Ai-M62 use bl616:
make CHIP=bl616 BOARD=bl616dkHold BOOT (IO2 on the Ai-M61-32S-Kit), briefly press EN/RST to enter download mode, then flash:
make flash CHIP=bl616 COMX=/dev/ttyUSB0Serial 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 3365On 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 3365Code 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 familySOCK_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 handleaddr:sockaddr_inwithhtons(port)andINADDR_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 socketbuf/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 socketTCP_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
/****************************************************************************
*
* 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
#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);
#endifFAQ
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

