1、实验简介参考网址https://gitee.com/Lockzhiner-Electronics/lz3863/tree/master/apps/c3_wifi_tcp_server1.1、实验目的本实验旨在帮助学习者掌握 OpenHarmony 轻量系统中WiFi TCP 服务端的基本使用方法。通过本实验你将学会理解TCP 协议的面向连接、可靠传输特性及客户端/服务端通信模型在开发板上以 STA 模式连接 WiFi 热点通过 DHCP 获取 IP 地址使用 lwIPSocket API创建 TCP 服务端完成绑定、监听、接受连接与数据收发掌握 TCP 服务端与客户端的完整联调流程完成案例代码的编译、烧录与串口现象观察。1.2、实验内容本案例在 LZ3863-星闪开发板上实现TCP 服务端功能先连接指定 WiFi 热点并获取 IP再在本机端口上创建 TCP 服务、等待客户端连接连接建立后发送初始测试数据并持续接收客户端数据全过程通过串口打印日志。项目说明源文件wifi_tcp_server_example.c主程序、wifi_connecter.cWiFi 封装WiFi 模式STA站点/客户端目标 SSIDlzdz目标密码88888888TCP 监听端口777绑定地址INADDR_ANY接受任意 IP 的客户端连接发送测试数据wifi_tcp_test_date任务线程tcp_server_demo_task栈大小 8192 字节初始化入口APP_FEATURE_INIT(tcp_server_demo_entry)典型联调拓扑┌─────────────────┐ WiFi ┌─────────────────┐ │ PC / 手机热点 │ ◄──────────────────► │ LZ3863 开发板 │ │ SSID: lzdz │ │ (TCP Server) │ │ │ TCP :777 │ IP: 192.168. │ │ (TCP Client) │ ◄──────────────────► │ 137.x │ └─────────────────┘ └─────────────────┘说明开发板作为 TCP 服务端需先通过串口日志确认其 DHCP 获取到的 IP 地址客户端PC 网络调试工具、nc命令或c2_wifi_tcp_client案例应连接该 IP 及端口777。1.3、实验环境项目说明硬件LZ3863-星闪开发板、USB 数据线软件OpenHarmony v5.1.0 源码、hb 编译工具网络环境可连接的 WiFi 热点SSID/密码与代码一致TCP 客户端PC 端网络调试工具 /nc/ Python 脚本或c2_wifi_tcp_client案例调试工具串口助手波特率 1152008N1案例路径applications/sample/wifi-iot/app/c3_wifi_tcp_server/2、基础知识2.1、TCP 协议概述TCPTransmission Control Protocol传输控制协议是一种面向连接的、可靠的传输层协议具有以下特点特性说明面向连接通信前需通过三次握手建立连接结束后四次挥手断开可靠传输通过序号、确认、重传机制保证数据不丢失、不重复全双工连接建立后双方可同时发送和接收数据字节流数据以连续字节流形式传输无固定报文边界TCP 通信采用客户端/服务端C/S模型角色职责本实验对应TCP 服务端绑定端口、监听连接、接受客户端请求本案例开发板TCP 客户端主动发起连接、发送/接收数据PC 或另一块开发板2.2、Socket 服务端编程基础Socket套接字是网络编程的抽象接口lwIP 提供了与 BSD Socket 兼容的 API。TCP 服务端的典型流程socket() → 创建套接字 ↓ 配置 sockaddr_inINADDR_ANY 端口 ↓ bind() → 绑定本地 IP 和端口 ↓ listen() → 进入监听状态 ↓ accept() → 阻塞等待客户端连接三次握手 ↓ send() / recv() → 与客户端收发数据 ↓ closesocket() → 关闭连接与 TCP 客户端的关键区别步骤TCP 客户端TCP 服务端本实验地址配置指定服务器 IP 端口INADDR_ANY 监听端口建立连接connect()主动连接bind()listen()accept()被动等待通信对象使用同一sockfd监听套接字sockfd 连接套接字connfd关键数据结构sockaddr_in服务端structsockaddr_inserver_addr{0};server_addr.sin_familyAF_INET;// IPv4server_addr.sin_porthtons(port);// 端口号转网络字节序server_addr.sin_addr.s_addrhtonl(INADDR_ANY);// 绑定所有网卡接受任意 IP 接入字节序转换函数作用htons()主机字节序 → 网络字节序16 位用于端口htonl()主机字节序 → 网络字节序32 位用于 IPinet_ntoa()二进制网络地址 → 字符串 IP用于打印客户端地址ntohs()网络字节序 → 主机字节序16 位用于端口2.3、WiFi STA 连接与网络层本案例在启动 TCP 服务之前需先通过ConnectToHotspot()完成 WiFi 连接与 IP 获取。完整流程为启用 STA 模式 → 扫描热点 → 匹配 SSID → 关联连接 → 启动 DHCP 客户端 → 获取 IP 地址 → 网络层就绪获取 IP 后开发板与 TCP 客户端处于同一局域网客户端可通过该 IP 地址和监听端口发起连接。2.4、软件调用层次本案例的软件调用层次如下应用层wifi_tcp_server_example.c ├── tcp_server_demo_entry() ← APP_FEATURE_INIT 注册入口 ├── tcp_server_demo_task() ← 任务线程WiFi 连接 TCP 服务端 └── tcp_server_test() ← TCP 核心逻辑 │ WiFi 封装层wifi_connecter.c └── ConnectToHotspot() ← 扫描、连接、DHCP 获取 IP │ 协议栈 / 驱动层 ├── lwIP Socket APIsocket/bind/listen/accept/send/recv ├── lwIP 网络协议栈TCP/IP、DHCP └── WiFi 驱动HMAC/DMAC2.5、核心 API 介绍2.5.1、头文件#includecmsis_os2.h#includelwip/sockets.h#includeohos_init.h#includeosal_debug.h#includewifi_connecter.h#includeerrno.h#includestdio.h#includestring.h#includeunistd.h2.5.2、Socket API服务端API 名称功能说明socket(AF_INET, SOCK_STREAM, 0)创建 IPv4 TCP 套接字返回套接字描述符bind(sockfd, addr, addrlen)将套接字绑定到指定的 IP 地址和端口listen(sockfd, backlog)使套接字进入监听状态等待客户端连接accept(sockfd, addr, addrlen)阻塞等待并接受客户端连接返回新的连接套接字send(sockfd, buf, len, flags)向已连接套接字发送数据返回实际发送字节数recv(sockfd, buf, len, flags)从已连接套接字接收数据返回实际接收字节数closesocket(sockfd)关闭套接字释放资源inet_ntoa(in_addr)将网络字节序 IP 地址转换为字符串2.5.3、WiFi 与应用层 APIAPI 名称功能说明ConnectToHotspot(ssid, password)扫描并连接指定热点完成 DHCP 获取 IPDisconnectWithHotspot()停止 DHCP 并断开 WiFi 连接osThreadNew(func, arg, attr)创建 RTOS 线程osDelay(ticks)线程延时100 ticks ≈ 1 秒tick 10 msAPP_FEATURE_INIT(func)注册应用特性初始化入口系统启动后自动执行3、程序设计3.1、程序架构本案例目录结构c3_wifi_tcp_server/ ├── wifi_tcp_server_example.c # TCP 服务端主程序 ├── wifi_connecter.c # WiFi 连接封装实现 ├── wifi_connecter.h # 封装接口头文件 ├── BUILD.gn # GN 编译配置 ├── README_zh.md # 案例简要说明 └── 实验手册.md # 本实验手册程序执行流程系统启动 │ ▼ tcp_server_demo_entry() ← APP_FEATURE_INIT 注册自动执行 │ ▼ osThreadNew(tcp_server_demo_task) ← 创建 TCP 服务端任务线程 │ ▼ tcp_server_demo_task() ├── ConnectToHotspot() ← 连接 WiFi 热点DHCP 获取 IP ├── osDelay(800) ← 等待网络稳定约 8 秒 └── tcp_server_test() ← 启动 TCP 服务端 ├── socket() ← 创建套接字 ├── bind() ← 绑定端口 777 ├── listen() ← 进入监听状态 ├── accept() ← 等待客户端连接 ├── send() ← 向客户端发送初始数据 ├── recv() 循环 ← 持续接收客户端数据 └── closesocket() ← 关闭连接3.2、源文件说明文件说明wifi_tcp_server_example.cTCP 服务端主程序包含 WiFi 连接、TCP 服务及任务线程wifi_connecter.cWiFi 封装实现ConnectToHotspot、StartHotspot、DisconnectWithHotspotwifi_connecter.h封装接口声明BUILD.gn编译配置生成wifi_tcp_server_example静态库3.3、关键代码分析1WiFi 与 TCP 配置参数#defineWIFI_SSIDlzdz#defineWIFI_PASSWORD88888888#defineTCP_SERVER_PORT777staticcharsend_data[50]wifi_tcp_test_date;staticcharrecv_data[100];实验前请根据实际网络环境修改WIFI_SSID和WIFI_PASSWORD确保与可用热点一致。TCP 监听端口可通过TCP_SERVER_PORT修改。2系统入口 — tcp_server_demo_entry通过APP_FEATURE_INIT注册应用入口创建tcp_server_demo_task线程staticvoidtcp_server_demo_entry(void){osThreadAttr_tattr{.nametcp_server_demo_task,.stack_size8192,.priorityosPriorityNormal};if(osThreadNew(tcp_server_demo_task,NULL,attr)NULL){printf([tcp_server_demo_entry] Failed to create tcp_server_demo_task!\r\n);}}APP_FEATURE_INIT(tcp_server_demo_entry);3任务线程 — tcp_server_demo_task任务线程先完成 WiFi 连接延时等待网络稳定后再启动 TCP 服务端staticvoidtcp_server_demo_task(void*arg){(void)arg;printf(Starting Wi-Fi connection to SSID: %s...\r\n,WIFI_SSID);if(ConnectToHotspot(WIFI_SSID,WIFI_PASSWORD)!0){printf(Failed to connect to AP.\r\n);return;}printf(Wi-Fi connected successfully.\r\n);osDelay(800);// 等待约 8 秒确保网络栈稳定tcp_server_test(TCP_SERVER_PORT);}4TCP 服务端核心 — tcp_server_testtcp_server_test()实现完整的 TCP 服务端通信流程voidtcp_server_test(unsignedshortport){ssize_tret0;intbacklog1;// 1. 创建 TCP 套接字intsockfdsocket(AF_INET,SOCK_STREAM,0);if(sockfd0){printf(Failed to create socket! errno%d\r\n,errno);return;}intconnfd-1;structsockaddr_inclient_addr{0};socklen_tclient_addr_lensizeof(client_addr);structsockaddr_inserver_addr{0};// 2. 配置服务端地址绑定所有网卡server_addr.sin_familyAF_INET;server_addr.sin_porthtons(port);server_addr.sin_addr.s_addrhtonl(INADDR_ANY);// 3. 绑定端口retbind(sockfd,(structsockaddr*)server_addr,sizeof(server_addr));if(ret0){printf(Bind to port %d failed! errno%d\r\n,port,errno);closesocket(sockfd);return;}printf(Bind to port %d success!\r\n,port);// 4. 进入监听状态retlisten(sockfd,backlog);if(ret0){printf(Listen on port %d failed! errno%d\r\n,port,errno);closesocket(sockfd);return;}printf(Listen with %d backlog success!\r\n,backlog);// 5. 阻塞等待客户端连接connfdaccept(sockfd,(structsockaddr*)client_addr,client_addr_len);if(connfd0){printf(Accept connection failed! errno%d\r\n,errno);closesocket(sockfd);return;}printf(Accepted connection, connfd%d\r\n,connfd);printf(Client info: IP%s, Port%d\r\n,inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));// 6. 向客户端发送初始数据retsend(connfd,send_data,strlen(send_data),0);if(ret0){printf(Send data to client failed! errno%d\r\n,errno);}else{printf(Sent data{%s} %ld bytes to client!\r\n,send_data,ret);}// 7. 持续接收客户端数据while(1){memset(recv_data,0,sizeof(recv_data));retrecv(connfd,recv_data,sizeof(recv_data)-1,0);if(ret0){printf(Recv data failed or connection closed! ret%ld, errno%d\r\n,ret,errno);break;}recv_data[ret]\0;printf(Received data{%s} from client!\r\n,recv_data);osDelay(100);// 防止忙等待}// 8. 关闭套接字closesocket(connfd);closesocket(sockfd);}设计要点INADDR_ANY表示绑定到所有可用网卡客户端可通过开发板的任意 IP 地址连接backlog 1表示等待队列最多容纳 1 个未完成连接accept()返回的connfd用于与客户端通信原sockfd仍用于监听本案例仅处理一个客户端recv()返回 0 表示客户端正常关闭连接返回负值表示出错。5WiFi 封装层 — ConnectToHotspot 概要ConnectToHotspot()在wifi_connecter.c中实现主要步骤调用wifi_sta_enable()启用 STA 模式循环执行wifi_sta_scan()扫描get_match_network()匹配目标 SSID调用wifi_sta_connect()发起关联等待WIFI_CONNECTED状态在wlan0接口上启动 DHCP 客户端获取 IP 地址并打印。3.4、程序执行流程TCP 客户端 (PC/开发板)WiFi 热点开发板 (TCP Server)TCP 客户端 (PC/开发板)WiFi 热点开发板 (TCP Server)连接关闭或出错时 closesocket()APP_FEATURE_INIT → tcp_server_demo_entryosThreadNew(tcp_server_demo_task)ConnectToHotspot(lzdz)关联成功 DHCP 分配 IPosDelay(800) 等待网络稳定bind(:777) listen()connect(开发板IP:777)accept() 三次握手完成send(wifi_tcp_test_date)客户端发送数据recv() 循环打印接收内容4、编译步骤以下步骤只需在首次编译时完成 4.14.3 的配置注册。4.1、确认案例目录确认案例已位于 OpenHarmony 源码目录下applications/sample/wifi-iot/app/c3_wifi_tcp_server/ ├── wifi_tcp_server_example.c ├── wifi_connecter.c ├── wifi_connecter.h ├── BUILD.gn └── 实验手册.md若从外部复制请将c3_wifi_tcp_server目录放到上述app/路径下。4.2、修改 BUILD.gn注册编译组件编辑applications/sample/wifi-iot/app/BUILD.gn在features列表中添加本案例lite_component(app) { features [ startup, c3_wifi_tcp_server:wifi_tcp_server_example, // 添加此行 ] }4.3、修改 SDK 配置文件步骤 1编辑device/soc/hisilicon/ws63v100/sdk/build/config/target_config/ws63/config.py找到ws63-liteos-app配置段在其ram_component列表中添加wifi_tcp_server_example步骤 2编辑device/soc/hisilicon/ws63v100/sdk/libs_url/ws63/cmake/ohos.cmake找到ws63-liteos-app对应的set(COMPONENT_LIST部分添加wifi_tcp_server_example4.4、编译固件在 OpenHarmony 源码根目录下执行编译rm-rfout hbset-root.# 通过上下方向键选择 ws63 对应的编译分支如 nearlink_dk_3863 / ws63-liteos-apphb build-f编译成功后使用开发板配套烧录工具将固件烧写到 LZ3863-星闪开发板。4.5、修改网络参数可选烧录前若实际 WiFi 热点与默认值不同请编辑wifi_tcp_server_example.c中的宏定义#defineWIFI_SSIDlzdz// 改为实际热点名称#defineWIFI_PASSWORD88888888// 改为实际热点密码#defineTCP_SERVER_PORT777// 改为实际监听端口修改后需重新编译并烧录。5、运行结果5.1、硬件与网络准备方式一PC 移动热点 PC 端 TCP 客户端推荐在 PC 上开启移动热点SSID 设为lzdz密码设为88888888开发板上电或复位烧录本案例固件通过 USB 连接 PC 打开串口助手1152008N1观察串口日志中打印的开发板 IP 地址如STA IP 192.168.137.x在 PC 上使用 TCP 客户端连接该 IP 及端口777# 方式 A使用 netcatLinux / macOSnc192.168.137.x777# 方式 B使用 Pythonpython3-c import socket s socket.socket() s.connect((192.168.137.x,777))print(Connected to server) data s.recv(1024) print(fReceived: {data.decode()}) s.send(bHello from TCP client!) s.close() 将192.168.137.x替换为串口日志中实际打印的开发板 IP。方式二使用 c2_wifi_tcp_client 案例联调准备可连接的 WiFi 路由器或手机热点SSID/密码与代码一致本开发板烧录c3_wifi_tcp_server固件作为 TCP 服务端另一块开发板烧录c2_wifi_tcp_client固件作为 TCP 客户端查看服务端串口日志中的 IP 地址将其填入客户端案例的TCP_SERVER_IP宏定义后重新编译烧录客户端固件。建议先确认开发板 WiFi 连接成功并打印 IP 地址再启动 TCP 客户端连接以提高首次联调成功率。5.2、串口配置参数值波特率115200数据位8停止位1校验位无流控无5.3、预期串口输出烧录固件并复位后串口助手可观察到完整的 WiFi 连接与 TCP 服务过程Starting Wi-Fi connection to SSID: lzdz... Start Scan ! [WIFI_STA_SAMPLE] Scan done!. STA try connect. [WIFI_STA_SAMPLE] Connect succ!. STA DHCP start. STA DHCP bound success. STA IP 192.168.137.x Connect success. Wi-Fi connected successfully. Bind to port 777 success! Listen with 1 backlog success! Accepted connection, connfd3 Client info: IP192.168.137.1, Portxxxxx Sent data{wifi_tcp_test_date} 18 bytes to client! Received data{Hello from TCP client!} from client!其中Start Scan !/Scan done!表示 WiFi 热点扫描完成Connect succ!/STA IP 192.168.137.x表示 WiFi 关联成功并获取 IPWi-Fi connected successfully.表示应用层确认 WiFi 就绪Bind to port 777 success!表示端口绑定成功Listen with 1 backlog success!表示 TCP 服务已进入监听状态Accepted connection表示客户端连接建立三次握手完成Sent data{wifi_tcp_test_date}表示初始数据发送成功Received data{...} from client!表示收到客户端发送的数据。5.4、PC 端 TCP 客户端预期现象若使用 netcat 或 Python 脚本作为客户端PC 端可观察到Connected to server Received: wifi_tcp_test_date表示开发板 TCP 服务端已成功接受连接并发送初始数据。5.5、结果分析现象说明输出Wi-Fi connected successfully.WiFi 连接与 DHCP 获取 IP 成功输出Bind to port 777 success!TCP 端口绑定成功输出Listen with 1 backlog success!TCP 服务进入监听状态输出Accepted connection客户端连接建立成功输出Sent data{wifi_tcp_test_date}初始数据发送成功输出Received data{...} from client!客户端数据接收成功输出Failed to connect to AP.WiFi 连接失败检查 SSID/密码输出Bind to port 777 failed!端口被占用或权限不足输出Accept connection failed!接受连接失败检查网络状态输出Recv data failed or connection closed客户端主动关闭连接或网络中断5.6、常见问题排查问题可能原因解决方法反复Can not find AP热点未开启或 SSID/密码不匹配确认热点已开启宏定义与实际一致WiFi 成功但客户端无法连接使用了错误的 IP 地址以串口打印的STA IP为准勿使用网关 IP客户端Connection refused服务端尚未进入 listen 状态等待Listen with 1 backlog success!后再连接Bind to port 777 failed!端口已被其他程序占用更换TCP_SERVER_PORT或重启开发板PC 端连接超时防火墙拦截或不在同一网段确认 PC 与开发板连接同一热点关闭防火墙编译报错找不到组件BUILD.gn 或 config.py 未修改逐步核对 4.2、4.3 节的配置项仅处理一个客户端代码设计为单连接模式正常现象连接断开后需重启开发板再次 accept6、实验扩展完成基本实验后可尝试以下扩展练习修改通信内容更改send_data字符串观察客户端接收到的数据变化双向通信在recv()循环中增加send()回发逻辑实现简单的请求-响应交互配合 TCP 客户端案例使用c2_wifi_tcp_client案例实现两块开发板之间的 TCP 通信多客户端支持使用select()或循环accept()支持多个客户端同时连接断线重连客户端断开后重新进入accept()等待新连接实现服务端持续运行设置 SO_REUSEADDR在bind()前设置地址复用选项避免端口占用问题改用 UDP 通信参考后续 UDP 案例对比 TCP 服务端与 UDP 在可靠性、效率上的差异。