Concepts First
- TCP client: the device that actively connects to a server. After
connect()succeeds, it can send and receive data over the connection. - Socket: the handle created by
socket(AF_INET, SOCK_STREAM, 0); all operations (connect/read/write/close) use it. - RX/TX tasks: the example forks two tasks — one continuously reads (
read), the other continuously writes (write) — to test bidirectional transfer. - Ctrl+C: the shell signal stops the client and prints total received/sent byte counts.
Example Overview
This page covers the TCP client part of the wifi_tcp example in the official Bouffalo SDK (examples/wifi/sta/wifi_tcp/wifi_tcp_client.c):
socket()creates a TCP socket,inet_addr()+htons()fill the server address,connect()establishes the connection;- two tasks
wifi_tcp_client_rx/wifi_tcp_client_txloopread()/write()every 200ms, handlingERR_TIMEOUTretries; - the shell command
wifi_tcp_test <ip> <port>starts the client; - optional
SO_SNDTIMEOreceive/send timeout can be enabled withTCP_CLIENT_BLOCK_TIMEOUT. - Sibling example: the same directory's
wifi_tcp_server.cprovides the echo server commandwifi_tcp_echo_test <port>(see TCP Server).
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, briefly press EN/RST to enter download mode, then flash:
make flash CHIP=bl616 COMX=/dev/ttyUSB0On the PC, listen on port 3365 with netcat:
nc -lp 3365Serial tool at 2000000 baud. Wait for bouffalolab />, connect to the router, then start the TCP client pointing at the PC’s IP and port:
wifi_sta_connect Your_SSID 12345678
wifi_tcp_test 192.168.1.2 3365The module logs TCP client connect server success! and creates RX/TX tasks; the PC’s netcat receives the wifi tcp client test, helloworld! payload repeatedly, and data typed on the PC is received by the module’s RX task.
Code Execution Flow
The complete flow from boot to bidirectional transfer:
APIs Used by the Example
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
Creates a TCP socket.
Parameters:
AF_INET: IPv4 address familySOCK_STREAM: stream (TCP) socket
Return: >= 0 handle; < 0 on failure
connect(sock, &remote_addr, sizeof(sockaddr))
Connects to the server address (IP + port).
Parameters:
sock: socket handleremote_addr:sockaddr_inwithsin_port = htons(port)andsin_addr = inet_addr(ip)
Return: 0 on success; nonzero on failure
read / write(sock, buf, len)
Read from / write to the connected socket. ERR_TIMEOUT means the non-blocking operation timed out.
Parameters:
sock: connected socketbuf/len: buffer and length
Return: bytes transferred; negative on error/timeout
shell_signal / closesocket(SHELL_SIGINT, cb) / (sock)
Registers a Ctrl+C handler that stops the tasks, then closes the socket and prints RX/TX totals.
Parameters:
SHELL_SIGINT: interrupt signalcb: handler (sig_close)
Return: none
Complete Code
The full wifi_tcp example sources related to the TCP client, 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_client.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"
#define TCP_CLIENT_BLOCK_TIMEOUT 0
#define TCP_CLIENT_NOT_DEL_SELF 0
struct arg_param {
int argc;
char **argv;
};
// clang-format off
static const uint8_t write_buf[128] = "wifi tcp client test, helloworld!\r\n";
static uint8_t read_buf[128];
// clang-format on
static volatile int wifi_tcp_client_exit;
static shell_sig_func_ptr abort_exec;
static uint64_t total_rx_cnt;
static uint64_t total_tx_cnt;
static void sig_close(int sig)
{
wifi_tcp_client_exit = 1;
if (abort_exec) {
abort_exec(sig);
}
}
#define PING_USAGE \
"wifi_tcp_test [ip] [port]\r\n" \
"\t ip: dest ip or server ip\r\n" \
"\t port: dest server listen port\r\n"
static void wifi_tcp_client_rx(void *sock_client)
{
printf("tcp client rx task start ...\r\n");
int sock = *(int*)sock_client;
int ret;
int timeout_cnt = 0;
/* read */
while (1) {
ret = read(sock, read_buf, sizeof(read_buf));
if (ret >= 0) {
total_rx_cnt += ret;
timeout_cnt = 0;
} else if (ret == ERR_TIMEOUT) {
if (++timeout_cnt > 3) {
printf("read failed, timeout_cnt: %d\n\r", timeout_cnt);
break;
}
} else {
printf("read failed, ret: %d, errno: %d\n\r", ret, errno);
break;
}
vTaskDelay(200);
}
/* wait to be deleted */
#if TCP_CLIENT_NOT_DEL_SELF
printf("tcp client rx task exiting...\r\n");
while (1) {
vTaskDelay(200);
}
#else
vTaskDelete(NULL);
#endif
printf("tcp client rx task exit!\r\n");
}
static void wifi_tcp_client_tx(void *sock_client)
{
printf("tcp client tx task start ...\r\n");
int sock = *(int*)sock_client;
int ret;
int timeout_cnt = 0;
/* write */
while (1) {
ret = write(sock, write_buf, sizeof(write_buf));
if (ret >= 0) {
total_tx_cnt += sizeof(write_buf);
timeout_cnt = 0;
} else if (ret == ERR_TIMEOUT) {
if (++timeout_cnt > 3) {
printf("write failed, timeout_cnt: %d\n\r", timeout_cnt);
break;
}
} else {
printf("write failed, ret: %d, errno: %d\n\r", ret, errno);
break;
}
vTaskDelay(200);
}
/* wait to be deleted */
#if TCP_CLIENT_NOT_DEL_SELF
printf("tcp client tx task exiting...\r\n");
while (1) {
vTaskDelay(200);
}
#else
vTaskDelete(NULL);
#endif
printf("tcp client tx task exit!\r\n");
}
static void wifi_tcp_client_init(void *input_arg)
{
printf("tcp client task start ...\r\n");
char *addr;
char *port;
int sock_client = -1;
struct sockaddr_in remote_addr;
TaskHandle_t px_tcpclient_rx_task = NULL;
TaskHandle_t px_tcpclient_tx_task = NULL;
struct arg_param* arg = (struct arg_param*)input_arg;
/* check arg */
if (arg->argc < 3) {
printf("%s", PING_USAGE);
goto __exit;
}
/* get address (argv[1] if present) */
addr = arg->argv[1];
/* get port number (argv[2] if present) */
port = arg->argv[2];
/* create socket */
if ((sock_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
printf("TCP Client create socket error\r\n");
goto __exit;
}
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(atoi(port));
remote_addr.sin_addr.s_addr = inet_addr(addr);
memset(&(remote_addr.sin_zero), 0, sizeof(remote_addr.sin_zero));
printf("Server ip Address : %s:%s\r\n", addr, port);
/* connect socket */
if (connect(sock_client, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) != 0) {
printf("TCP client connect server falied!\r\n");
goto __exit;
}
printf("TCP client connect server success!\r\n");
#if TCP_CLIENT_BLOCK_TIMEOUT
/* blocking timeout */
int timeout_ms = 4000;
#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
int opt_on = timeout_ms;
#else
struct timeval opt_on = {
.tv_sec = timeout_ms / 1000,
.tv_usec = (timeout_ms - (opt_on.tv_sec * 1000)) * 1000,
};
#endif
setsockopt(sock_client, SOL_SOCKET, SO_SNDTIMEO, (void *)&opt_on, sizeof(opt_on));
#endif
total_rx_cnt = 0;
total_tx_cnt = 0;
wifi_tcp_client_exit = 0;
abort_exec = shell_signal(SHELL_SIGINT, sig_close);
printf("Press CTRL-C to exit before next Shell CMD.\r\n");
/* fork recv and send task, dont care fail */
xTaskCreate(wifi_tcp_client_rx, "tcp_client_rx", 512, (void *)&sock_client, 20, &px_tcpclient_rx_task);
xTaskCreate(wifi_tcp_client_tx, "tcp_client_tx", 512, (void *)&sock_client, 20, &px_tcpclient_tx_task);
while (!wifi_tcp_client_exit) {
vTaskDelay(500);
}
__exit:
/* exit procedure */
if (sock_client >= 0) {
printf("closesocket!\r\n");
closesocket(sock_client);
}
if (px_tcpclient_rx_task || px_tcpclient_tx_task) {
vTaskDelay(500);
}
#if TCP_CLIENT_NOT_DEL_SELF
if (px_tcpclient_rx_task) {
vTaskDelete(px_tcpclient_rx_task);
}
if (px_tcpclient_tx_task) {
vTaskDelete(px_tcpclient_tx_task);
}
#endif
if (total_rx_cnt || total_tx_cnt) {
printf("Total recv data=%lld\r\n", total_rx_cnt);
printf("Total send data=%lld\r\n", total_tx_cnt);
}
printf("tcp_client exit!\r\n");
vTaskDelete(NULL);
}
#ifdef CONFIG_SHELL
#include <shell.h>
int cmd_wifi_tcp_client(int argc, char **argv)
{
struct arg_param arg = {argc, argv};
if (pdPASS != xTaskCreate(wifi_tcp_client_init, "tcp_client", 512, (void *)&arg, 15, NULL)) {
return -1;
}
return 0;
}
SHELL_CMD_EXPORT_ALIAS(cmd_wifi_tcp_client, wifi_tcp_test, wifi tcp test);
#endifFAQ
TCP client connect server falied
Confirm the module is connected to Wi-Fi, the PC is on the same subnet, the server is actually listening (nc -lp 3365), and the firewall allows inbound TCP on that port.
PC receives data but the module's read task shows nothing
The RX task prints only after it reads data; type something in the netcat window and press Enter — the data is sent to the module and printed via the read buffer. Baud rate and terminal line endings can also affect display.
Have questions?
For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

