【鸿蒙开发】Hi3861学习笔记- TCP客户端

00. 目录

文章目录

    • [00. 目录](#00. 目录)
    • [01. TCP概述](#01. TCP概述)
    • [02. TCP应用场景](#02. TCP应用场景)
    • [03. TCP和UDP比较](#03. TCP和UDP比较)
    • [04. TCP相关API](#04. TCP相关API)
    • [05. TCP编程流程](#05. TCP编程流程)
    • [06. 硬件设计](#06. 硬件设计)
    • [07. 软件设计](#07. 软件设计)
    • [08. 实验现象](#08. 实验现象)
    • [09. 附录](#09. 附录)

01. TCP概述

TCP(Transmission Control Protocol)是一种面向连接可靠的传输层协议,旨在通过严格的传输控制机制,确保数据在IP网络中的有序、完整传输。与UDP不同,TCP通过流量控制、拥塞控制和重传机制为应用层提供高可靠性,适用于对数据准确性要求严苛的场景。

核心特点

面向连接

通信前需通过三次握手 建立端到端连接,结束后通过四次挥手释放连接,确保通信双方状态同步。

可靠传输

  • 数据分片与重组:将大数据分割为报文段传输,接收端按序列号重组。
  • 确认应答(ACK):接收方需返回ACK确认收到数据,否则发送方重传。
  • 超时重传:未收到ACK时,自动重发丢失的报文段。

顺序控制

每个报文段携带唯一序列号(Sequence Number),接收端严格按序重组数据。

流量控制

通过滑动窗口机制动态调整发送速率,防止接收方缓冲区溢出。

拥塞控制

根据网络状况动态调整发送窗口,避免网络过载(如慢启动、拥塞避免算法)。

02. TCP应用场景

  1. Web通信
    HTTP/HTTPS(网页浏览)、SSL/TLS加密传输。
  2. 文件传输
    FTP(文件上传下载)、SFTP(安全文件传输)。
  3. 邮件服务
    SMTP(发送邮件)、POP3/IMAP(接收邮件)。
  4. 远程管理
    SSH(安全远程登录)、Telnet(远程终端)。
  5. 数据库操作
    MySQL、PostgreSQL等数据库协议依赖TCP保证事务完整性。

常见基于TCP的协议

  • HTTP/HTTPS(网页传输)
  • FTP/SFTP(文件传输)
  • SMTP/POP3/IMAP(电子邮件)
  • SSH(安全远程登录)
  • MySQL/Redis(数据库协议)

03. TCP和UDP比较

特性 TCP UDP
连接方式 面向连接(三次握手/四次挥手) 无连接
可靠性 可靠传输,自动重传 不可靠,不重传
数据顺序 严格保证顺序 不保证顺序
流量控制 滑动窗口机制
拥塞控制 动态调整发送速率
头部大小 最小20字节(可扩展) 8字节
适用场景 数据完整性 > 实时性 实时性 > 可靠性

04. TCP相关API

以下 TCP 接口位于 vendor\hisi\hi3861\hi3861\third_party\lwip_sack\include\sockets.h

  • socket()

  • bind()

  • accept()

  • shutdown()

  • getpeername()

  • getsockopt()setsockopt()

  • close()

  • read()readv()write()writev()

  • recv()

  • send()sendmsg()sendto()

  • select()

  • fcntl()

05. TCP编程流程

5.1 新建socket

c 复制代码
int sock_fd;

//创建socket
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
    perror("create socket failed!\r\n");
    exit(1);
}

5.2 配置将要连接的服务器信息(端口和IP)

c 复制代码
#define TCP_SERVER_ADRESS    "192.168.31.170"    // 要连接TCP服务器地址
#define TCP_PORT             8888                // 要连接TCP服务器端口号

int addr_length;

//服务器的地址信息
struct sockaddr_in send_addr;

//初始化预连接的服务端地址
send_addr.sin_family = AF_INET;
send_addr.sin_port = htons(TCP_PORT);
send_addr.sin_addr.s_addr = inet_addr(TCP_SERVER_ADRESS);
addr_length = sizeof(send_addr);

5.3 连接服务器

c 复制代码
connect(sock_fd, (struct sockaddr *)&send_addr, addr_length);

5.4 发送数据

c 复制代码
static const char *send_data = "Hello! I'm BearPi-HM_Nano TCP Client!\r\n";

while (1) 
{
    ······

    //发送数据到服务远端
    int ret;
    if((ret = send(sock_fd, send_data, strlen(send_data), 0)) == -1)
    {
        perror("send:");
    }
    ······
}

5.5 接收数据

c 复制代码
char recvBuf[512];

int ret;
//接收服务端返回的字符串
if((ret = recv(sock_fd, recvBuf, sizeof(recvBuf), 0)) == -1)
{
    printf("recv error\r\n");
}
printf("recv:%s\r\n", recvBuf);

5.6 关闭连接

c 复制代码
//关闭这个 socket
closesocket(sock_fd);

06. 硬件设计

由于 Hi3861 内置 WIFI 功能,所以直接在开发板上使用即可,无需额外连接

07. 软件设计

bsp_wifi.h

c 复制代码
#ifndef __BSP_WIFI_H__
#define __BSP_WIFI_H__


#include "cmsis_os2.h"
#include "hi_io.h"
#include "hi_gpio.h"
#include "wifi_error_code.h"
#include "wifi_device.h"

//函数声明
WifiErrorCode WiFi_createHotSpots(const char *ssid, const char *psk);

WifiErrorCode WiFi_connectHotspots(const char *ssid, const char *psk);

#endif /* __BSP_WIFI_H__ */

bsp_wifi.c

c 复制代码
#include <unistd.h>
#include <stdio.h>
#include <string.h>

#include "wifi_device.h"
#include "wifi_hotspot.h"
#include "lwip/netifapi.h"
#include "lwip/netif.h"
#include "lwip/ip4_addr.h"
#include "lwip/api_shell.h"
#include "bsp_wifi.h"



//WIFI通道
#define WIFI_CHANNEL    5

#define DEF_TIMEOUT 15

#define SELECT_WLAN_PORT "wlan0"

//STA 连接状态结果
int g_ConnectState = 0;

struct netif *g_lwip_netif = NULL;

//----------------------------WIFI AP----------------------------------
/** Hotspot state change */
void OnHotspotStateChangedCallbak(int state)
{
    printf("OnHotspotStateChangedCallbak: state is %d.\n", state);
    if (WIFI_HOTSPOT_ACTIVE == state)
    {
        printf("wifi hotspot active\n");
    }
    else
    {
        printf("wifi hotspot noactive\n");
    }
}

/** Station connected */
void OnHotspotStaJoinCallbak(StationInfo *info)
{
    static char macAddr[32] = {0};
    static unsigned char *mac = NULL;

    if (NULL == info)
    {
        printf("OnHotspotStaJoinCallbak is NULL\n");
    }
    else
    {
        mac = info->macAddress;
        snprintf(macAddr, sizeof(macAddr), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

        printf("OnHotspotStaJoinCallbak: mac: %s reason: %d\n", macAddr, info->disconnectedReason);
    }
}

/** Station disconnected */
void OnHotspotStaLeaveCallbak(StationInfo *info)
{
    static char macAddr[32] = {0};
    static unsigned char *mac = NULL;

    if (NULL == info)
    {
        printf("OnHotspotStaLeaveCallbak is NULL\n");
    }
    else
    {
        mac = info->macAddress;
        snprintf(macAddr, sizeof(macAddr), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

        printf("OnHotspotStaLeaveCallbak: mac: %s reason: %d\n", macAddr, info->disconnectedReason);
    }

}

//创建Wifi热点
WifiErrorCode WiFi_createHotSpots(const char *ssid, const char *psk)
{
    WifiErrorCode ret;

    static WifiEvent event;

    static HotspotConfig config;

    printf("Start Initialization of WiFI AP Mode\r\n");

    //注册WIFI事件的回调函数
    event.OnHotspotStaJoin = OnHotspotStaJoinCallbak;
    event.OnHotspotStaLeave = OnHotspotStaLeaveCallbak;
    event.OnHotspotStateChanged =OnHotspotStateChangedCallbak;
    ret = RegisterWifiEvent(&event);
    if (WIFI_SUCCESS != ret)
    {
        printf("RegisterWifiEvent failed....\n");
        return -1;
    }
    printf("RegisterWifiEvent OK .....\n");

    //设置热点
    strcpy(config.ssid, ssid);
    strcpy(config.preSharedKey, psk);
    config.band = HOTSPOT_BAND_TYPE_2G;
    config.channelNum = WIFI_CHANNEL;
    config.securityType = WIFI_SEC_TYPE_PSK;
    ret = SetHotspotConfig(&config);
    if (WIFI_SUCCESS != ret)
    {
        printf("SetHotspotConfig failed....\n");
        return -1;
    }
    printf("SetHotspotConfig OK....\n");

    //启动WIFI AP模式
    ret = EnableHotspot();
    if (WIFI_SUCCESS != ret)
    {
        printf("EnableHotspot failed...\n");
        return -1;
    }
    printf("EnableHotspot OK ....\n");

    //检查热点模式是否使能
    if (WIFI_HOTSPOT_ACTIVE != IsHotspotActive())
    {
        printf("IsHotspotActive failed....\n");
        return -1;
    }
    printf("IsHotspotActive OK .....\n");
}


//----------------------------WIFI STA----------------------------------


/** Connection state change */
void staOnWifiConnectionChanged(int state, WifiLinkedInfo *info)
{
    if (state > 0)
    {
        g_ConnectState = 1;
        printf("staOnWifiConnectionChanged state: %d\n", state);
    }
    else
    {
        printf("staOnWifiConnectionChanged failed state: %d\n", state);
    }
    
}

/** Scan state change */
void staOnWifiScanStateChanged(int state, int size)
{
    printf("staOnWifiScanStateChanged state: %d size: %d\n", state, size);
}

/** Hotspot state change */
void staOnHotspotStateChanged(int state)
{
    printf("staOnHotspotStateChanged state: %d\n", state);
}

/** Station connected */
void staOnHotspotStaJoin(StationInfo *info)
{
    printf("staOnHotspotStaJoin STA Join AP\n");
}

/** Station disconnected */
void staOnHotspotStaLeave(StationInfo *info)
{
    printf("staOnHotspotStaLeave..\n");
}


//STA模式 连接WIFI
WifiErrorCode WiFi_connectHotspots(const char *ssid, const char *psk)
{
    WifiErrorCode ret;

    static WifiEvent event;
    static WifiDeviceConfig config;
    int result;
    int timeout;

    printf("---------------WIFI STA Mode------------\n");
    //1. 注册WIFI事件
    event.OnHotspotStaJoin = staOnHotspotStaJoin;
    event.OnHotspotStaLeave = staOnHotspotStaLeave;
    event.OnHotspotStateChanged = staOnWifiScanStateChanged;
    event.OnWifiConnectionChanged = staOnWifiConnectionChanged;
    event.OnWifiScanStateChanged = staOnWifiScanStateChanged;
    ret = RegisterWifiEvent(&event);
    if (WIFI_SUCCESS != ret)
    {
        printf("RegisterWifiEvent failed....\n");
        return -1;
    }
    else
    {
        printf("RegisterWifiEvent OK....\n");
    }

    //2. 使能WIFI
    ret = EnableWifi();
    if (WIFI_SUCCESS != ret)
    {
        printf("EnableWifi failed...\n");
        return -1;
    }

    //3. 判断WIFI是否激活
    if (WIFI_STA_ACTIVE != IsWifiActive())
    {
        printf("IsWifiActive is not actived..\n");
        return -1;
    }

    //4. 配置连接热点信息
    strcpy(config.ssid, ssid);
    strcpy(config.preSharedKey, psk);
    config.securityType = WIFI_SEC_TYPE_PSK;
    ret = AddDeviceConfig(&config, &result);
    if (WIFI_SUCCESS != ret)
    {
        printf("AddDeviceConfig failed....\n");
        return -1;
    }

    //5. 连接到热点
    if (WIFI_SUCCESS == ConnectTo(result))
    {
        printf("ConnectTo OK.....\n");
    }
    else
    {
        printf("ConnectTo failed....\n");
        return -1;
    }

    //6. 等待连接结果
    timeout = DEF_TIMEOUT;
    while(timeout > 0)
    {
        sleep(1);
        timeout--;
        if (1 == g_ConnectState)
        {
            printf("Connect to %s OK ....\n", ssid);
            break;
        }
    }
    if (timeout <= 0)
    {
        printf("Connect to %s timeout.....\n", ssid);
        return -1;
    }

    //7. 获取网络接口
    g_lwip_netif = netifapi_netif_find(SELECT_WLAN_PORT);


    //8. 启动DHCP
    if (NULL != g_lwip_netif)
    {
        dhcp_start(g_lwip_netif);
        printf("dhcp_start begin dhcp....\n");
    }

    //9. 等待DHCP
    for (;;)
    {
        if (dhcp_is_bound(g_lwip_netif) == ERR_OK)
        {
            //打印获取到的IP信息
            netifapi_netif_common(g_lwip_netif, dhcp_clients_info_show, NULL);
            break;
        }

        printf("DHCP IP InProgress.....\n");
        sleep(1);
    }

    //10. 执行其它操作

}

template.c

c 复制代码
#include <stdio.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "bsp_wifi.h"
#include "lwip/sockets.h"

#define TASK_STACK_SIZE 1024

static const char *data = "hello shenzhen";


//任务1ID
osThreadId_t task1_id;
osThreadId_t task2_id;


//线程回调入口函数
void task1 (void *argument)
{
    int sockfd = -1;
    int ret = -1;
    char buf[128];
    struct sockaddr_in addr;

    //连接到WIFI
    WiFi_connectHotspots("IOT", "iot12345678");

    //创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
    {
        perror("socket");
        return;
    }
    printf("sockfd = %d\n", sockfd);


    //初始化预连接的服务端地址
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(10086);
    addr.sin_addr.s_addr = inet_addr("192.168.16.51");

    //连接到服务端
    ret = connect(sockfd, &addr, sizeof(addr));
    if (-1 == ret)
    {
        perror("connect");
        return;
    }
    printf("connect to server OK....\n");


    //数据发送和接收
    while(1)
    {
        ret = send(sockfd, data, strlen(data), 0);
        if (-1 == ret)
        {
            perror("send");
            break;
        }
        printf("send: %s ret: %d\n", data, ret);


        memset(buf, 0, sizeof(buf));
        ret = recv(sockfd, buf, sizeof(buf), 0);
        if (-1 == ret)
        {
            perror("recv");
            break;
        }
        printf("recv: %s ret: %d\n", buf, ret);

        sleep(1);
    }

    //关闭连接
    closesocket(sockfd);

}



/**
 * @description: 初始化并创建任务
 * @param {*}
 * @return {*}
 */
static void template_demo(void)
{  
    osThreadAttr_t attr;
    attr.name = "task1"; //任务名称
    attr.attr_bits = osThreadDetached; //分离状态
    attr.cb_mem = NULL;
    attr.cb_size = 0;
    attr.stack_mem = NULL;
    attr.stack_size = TASK_STACK_SIZE * 10;
    attr.priority = osPriorityNormal;


    //创建任务1
    task1_id = osThreadNew(task1, NULL, &attr);
    if (NULL != task1_id)
    {
        printf("任务1创建OK task1_id = %d\n", task1_id);
    }

}
SYS_RUN(template_demo);

08. 实验现象

09. 附录

相关推荐
抓鱼猫L1 分钟前
鸿蒙Next(四)文字识别
harmonyos
为什么要内卷,摆烂不香吗7 分钟前
HCIP之VRRP
网络
技术小齐8 分钟前
网络运维学习笔记(DeepSeek优化版)026 OSPF vlink(Virtual Link,虚链路)配置详解
运维·网络·学习
IT乐手40 分钟前
3.7、HarmonyOS Next 自定义弹窗(CustomDialog)
harmonyos
李游Leo1 小时前
HarmonyOS:ArkTS 多态样式自学指南
harmonyos
zacksleo1 小时前
鸿蒙Flutter实战:20. Flutter集成高德地图,同层渲染
flutter·harmonyos
李游Leo1 小时前
HarmonyOS:ArkTS RowSplit 组件自学指南
harmonyos
NodeMedia1 小时前
如何快速集成NodeMediaClient-Harmony
harmonyos
IT乐手1 小时前
3.8、HarmonyOS Next 气泡提示(Popup)
harmonyos
zacksleo1 小时前
鸿蒙Flutter实战:19-Flutter集成高德地图,跳转页面方式
flutter·harmonyos