【鸿蒙开发】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. 附录

相关推荐
半青年13 分钟前
华为鸿蒙电脑能否作为开发机?开发非鸿蒙应用?
ide·华为·编辑器·电脑·idea·harmonyos·visual studio
小突突突1 小时前
个人博客系统测试报告
运维·网络·功能测试
triticale2 小时前
【Java】网络编程(Socket)
java·网络·socket
wanhengidc2 小时前
服务器中存储空间不足该怎么办?
运维·服务器·网络
soulermax2 小时前
数字ic后端设计从入门到精通4(含fusion compiler, tcl教学)CMOS VLSI Design
网络·硬件架构
bestadc3 小时前
鸿蒙 核心与非核心装饰器
harmonyos
bing_1584 小时前
什么是IoT长连接服务?
网络·物联网·长连接服务
@兔然暴富@4 小时前
#跟着若城学鸿蒙# HarmonyOS NEXT学习之AlphabetIndexer组件详解
harmonyos
christine-rr4 小时前
【25软考网工】第六章(4)VPN虚拟专用网 L2TP、PPTP、PPP认证方式;IPSec、GRE
运维·网络·网络协议·网络工程师·ip·软考·考试
小白自救计划4 小时前
网络协议分析 实验四 ICMPv4与ICMPv6
网络·网络协议