当前位置: 首页 > news >正文

ESP-C3入门10. 创建TCP Client

ESP-C3入门10. 创建TCP Client

  • 一、创建 tcp client的一般步骤
    • 1. 创建 tcp 套接字
    • 2. 配置服务器地址
    • 3. 连接服务器
    • 4. 发送数据
    • 5. 接收数据
    • 6. 关闭套接字
  • 二、创建tcp_client任务
  • 三、示例代码
    • 1. tcpClient.h
    • 2. tcpClient.c
    • 3. main.c

在这里插入图片描述

一、创建 tcp client的一般步骤

本文示例使用的是阻塞IO进行网络通讯。 在高性能的网络编程中,可能会使用非阻塞IO或异步IO进行网络通讯。

1. 创建 tcp 套接字

使用 socket函数:

int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);

2. 配置服务器地址

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
inet_pton(AF_INET, server_ip, &server_addr.sin_addr);

3. 连接服务器

int ret = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret != 0) {ESP_LOGE(TAG, "Failed to connect to server, errno=%d", errno);close(sock);return;
}

4. 发送数据


int bytes_sent = send(sock, send_buf, send_len, 0);
if (bytes_sent < 0) {ESP_LOGE(TAG, "Failed to send data to server, errno=%d", errno);close(sock);return;
}

5. 接收数据

// 接收数据
int bytes_recv = recv(sock, recv_buf, recv_buf_size, 0);
if (bytes_recv < 0) {ESP_LOGE(TAG, "Failed to receive data from server, errno=%d", errno);close(sock);return;
}

6. 关闭套接字

close(sock);

二、创建tcp_client任务

由于网络通信涉及到阻塞IO操作,如果在主线程中直接调用网络API,会导致主线程被阻塞,无法处理其他任务。为了避免这种情况发生,可以将网络通信放在RTOS任务中处理,使得主线程可以继续运行。
另外,使用RTOS任务的好处还在于可以方便地控制任务的优先级、堆栈大小等参数,以及在需要的时候暂停、恢复、删除任务等操作。这样可以更加灵活地管理程序中的各个任务,实现复杂的多任务协作。
示例使用 xTaskCreate函数创建freeRTOS的任务:

xTaskCreate(tcp_client_task, "tcp_client_task", 4096, NULL, 5, NULL);

任务优先级是5,栈大小是4096

定义连接tcp 的任务时,注意需要保留参数:

void tcp_client_task(void* pvParameters);

三、示例代码

本示例会接前面章节连接WIFI的部分,帮wifi.c wifi.h部分代码不重复编写 。
下面示例中,tcpClient连接上服务器后,会发送ping消息,并等待服务器回应。如果服务器回应pong,则握手成功, 客户端继续发送10个报文, 然后关闭连接,重新请求连接服务端。

参考项目目录结构如下:
在这里插入图片描述

1. tcpClient.h

//
// Created by hs26661 on 2023/2/16.
//#ifndef ESP32_LEARN_TCPCLIENT_H
#define ESP32_LEARN_TCPCLIENT_H#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
void tcp_client_task(void* pvParameters);#endif //ESP32_LEARN_TCPCLIENT_H

2. tcpClient.c

//
// Created by hs26661 on 2023/2/16.
//
#include <lwip/sockets.h>
#include <esp_log.h>#define SERVER_HOST "192.18.200.28"
#define SERVER_PORT 3000
#define MESSAGE "ping"
#define MAX_RETRY 5 // 最大重试次数
#define DATA_SIZE 256 // 数据包大小static const char *TAG = "TCP_CLIENT";/*** 创建 freeRtos任务, 这里的参数注意不能删除* @param pvParameters*/
void tcp_client_task(void* pvParameters){// 重试次数int retry_count = 0;// 接收缓冲区char rx_buffer[DATA_SIZE];// 发送缓冲区char tx_buffer[DATA_SIZE];while(1){// 创建套接字struct sockaddr_in dest_addr;dest_addr.sin_addr.s_addr = inet_addr(SERVER_HOST);dest_addr.sin_family = AF_INET;dest_addr.sin_port = htons(SERVER_PORT);int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);// 连接服务端int err = connect(sock, (struct sockaddr*) &dest_addr, sizeof(dest_addr));if(err != 0){if(retry_count++ >= MAX_RETRY){ESP_LOGE(TAG, "connect failure retry limit");break;}ESP_LOGW(TAG, "connect failure, retry count=%d", retry_count);vTaskDelay(2000 / portTICK_PERIOD_MS);continue;}ESP_LOGI(TAG, "connect to server success");retry_count = 0;// 发送pingint tx_len = sprintf(tx_buffer, MESSAGE);err = send(sock, tx_buffer, tx_len, 0);if(err <0){ESP_LOGE(TAG, "send ping failure");close(sock);continue;}// 接收pongint rx_len = recv(sock,rx_buffer, sizeof(rx_buffer) -1, 0);if(rx_len<0){ESP_LOGE(TAG, "receive pong failure");close(sock);continue;}rx_buffer[rx_len] = 0;if(strcmp(rx_buffer, "pong") !=0){ESP_LOGE(TAG, "handshake failure");close(sock);continue;}ESP_LOGI(TAG, "handshake success");// 发送数据包for(int i =0;i<10;i++){// 获取当前时间字符串time_t now = time(NULL);struct tm timeinfo;localtime_r(&now, &timeinfo);char strftime_buf[64];strftime(strftime_buf , sizeof(strftime_buf), "%c", &timeinfo);// 发送数据包tx_len = sprintf(tx_buffer, "time:%s", strftime_buf);err = send(sock, tx_buffer, tx_len, 0);if(err <0){ESP_LOGE(TAG, "send data error");close(sock);break;}ESP_LOGI(TAG, "send data %d success", i+1);// 5秒后再发送vTaskDelay(5000 / portTICK_PERIOD_MS);}// 发送byetx_len = sprintf(tx_buffer, "bye");err = send(sock, tx_buffer, tx_len, 0);if(err<0){ESP_LOGE(TAG, "send bye error");close(sock);continue;}// 关闭连接close(sock);ESP_LOGI(TAG, "connection closed");// 重建 连接ESP_LOGI(TAG, "reconnect");vTaskDelay(2000/ portTICK_PERIOD_MS);}vTaskDelete(NULL);
}

3. main.c

#include <string.h>#include "freertos/FreeRTOS.h"
#include "freertos/task.h"#include <nvs_flash.h>
#include "network/include/wifi.h"
#include "network/include/tcpClient.h"static const char *TAG = "wifi connection";void app_main()
{int i = 0;ESP_LOGE(TAG, "app_main");// 初始化NVS存储区esp_err_t ret = nvs_flash_init();if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();}ESP_ERROR_CHECK(ret);// Wi-Fi初始化ESP_LOGI(TAG, "Wi-Fi initialization");wifi_initialize();// Wi-Fi Station初始化wifi_station_initialize();// 创建 tcp client任务,优先级为5,栈大小为4096xTaskCreate(tcp_client_task, "tcp_client_task", 4096, NULL, 5, NULL);while (1) {vTaskDelay(pdMS_TO_TICKS(500));}
}

运行结果:
在这里插入图片描述
示例中使用阻塞IO通讯,也可以将收发放在不同的任务中执行,这样提高程序并发性;在这种情况下,可以创建两个套接字并使用同一服务器地址和端口号。在发送和接收数据时,将不同的套接字分别用于不同的任务,从而实现并发的发送和接收。

具体来说,在两个任务中,需要使用不同的套接字句柄(socket handle)来访问相同的服务器地址和端口。在每个任务中,可以通过调用 socket()、connect() 和 close() 等函数来创建和管理套接字。发送和接收数据时,需要在每个任务中使用不同的套接字句柄来分别发送和接收数据。

需要注意的是,如果两个任务共用同一套接字句柄来进行发送和接收,那么就可能会出现竞争条件,导致数据错误或不完整。因此,为了避免这种情况,最好在每个任务中分别使用独立的套接字来进行通信。

本文不演示上述方案。

相关文章:

ESP-C3入门10. 创建TCP Client

ESP-C3入门10. 创建TCP Client一、创建 tcp client的一般步骤1. 创建 tcp 套接字2. 配置服务器地址3. 连接服务器4. 发送数据5. 接收数据6. 关闭套接字二、创建tcp_client任务三、示例代码1. tcpClient.h2. tcpClient.c3. main.c一、创建 tcp client的一般步骤 本文示例使用的…...

【Vue】浅谈vue2、vue3响应式原理,vue中数组的响应式,响应式常见问题分析

前言&#xff1a;此处响应式指的是数据响应式变化&#xff0c;而不是页面的响应式布局&#xff0c;页面的响应式布局在我的其他文章中有提到。 一、什么是vue响应式 Vue 最标志性的功能就是其低侵入性的响应式系统。组件状态都是由响应式的 JavaScript 对象组成的。当更改它们…...

股航顶峰先锋一号

{选股} TT:MA(C,30)>MA(C,60) AND MA(C,60)>MA(C,120);{均线多头} DD:C>REF(C,1);{收阳线} QQ:V>REF(V,1);{放量}; TT1:COUNT(L<MA(C,13),5)1; TT2:(C-REF(C,1))/REF(C,1)*100>3; DD1:V>REF(V,1)*2 AND C>REF(C,1); DD2:TT1 AND 0<MA(C,13)AND TT2 …...

MYSQL安装部署--Linux 仓库安装

声明 &#xff1a;# 此次我们安装的 MYSQL 版本是 8.0.32 版本 我们本次安装 MYSQL 总共要介绍 四种方式 # 仓库安装# 本地安装# 容器安装# 源码安装我们本篇介绍的是 仓库安装 仓库安装 下载 MYSQL 安装包 # MYSQL 安装&#xff0c;我们都是基于 MYSQL 官方网站里进行下载~&a…...

NFS服务器搭建

NFS服务器搭建1. NFS简介2. NFS工作原理3. 配置NFS服务端3.1 启动服务3.2 修改配置文件4. 配置NFS客户端1. NFS简介 NFS是Network File System的简写,即网络文件系统. 网络文件系统是FreeBSD支持的文件系统中的一种&#xff0c;也被称为NFS。 NFS允许一个系统在网络上与他人共…...

【数据挖掘实战】——航空公司客户价值分析(K-Means聚类案例)

目录 一、背景和挖掘目标 1、RFM模型缺点分析 2、原始数据情况 3、挖掘目标 二、分析方法与过程 1、初步分析&#xff1a;提出适用航空公司的LRFMC模型 2、总体流程 第一步&#xff1a;数据抽取 第二步&#xff1a;探索性分析 第三步&#xff1a;数据预处理 第四步&…...

AnlogicFPGA-IO引脚约束设置

&#xff08;https://www.eefocus.com/article/472120.html此链接是一篇关于XillinxFPGA的IO的状态分析&#xff0c;希望自己也要能了解到AnLogic的IO状态并有对此问题的分析能力&#xff09; 1、DriveStrength: 驱动强度&#xff0c;即最大能驱动的电流大小&#xff08;见带负…...

Java SSM 笔记(一)重置版

Spring核心技术 **前置课程要求&#xff1a;**请各位小伙伴先完成《JavaWeb》篇、《Java 9-17新特性》篇视频教程之后&#xff0c;再来观看此教程。 **建议&#xff1a;**对Java开发还不是很熟悉的同学&#xff0c;最好先花费半个月到一个月时间大量地去编写小项目&#xff0…...

centos安装java,目录授权

centos安装java (1)查看可安装版本: yum -y list java* 安装&#xff1a;sudo yum -y install java-17-openjdk.x86_64 验证&#xff1a;java –version (2)二进制安装&#xff1a;下载&#xff1a;wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.…...

【大数据】HADOOP-YARN容量调度器多队列配置详解实战

简介 Capacity调度器具有以下的几个特性&#xff1a; 层次化的队列设计&#xff0c;这种层次化的队列设计保证了子队列可以使用父队列设置的全部资源。这样通过层次化的管理&#xff0c;更容易合理分配和限制资源的使用。容量保证&#xff0c;队列上都会设置一个资源的占比&a…...

加密技术在android系统安全中的应用

前言android 系统安全内容总结 1、算法基础 算法基础参照linux的全盘加密与文件系统加密在android中的应用的2、预备知识 android系统安全特性用到加密算法的如下表:...

KNN&K-means从入门到实战

作者&#xff1a;王同学 来源&#xff1a;投稿 编辑&#xff1a;学姐 1. 基本概念 1.1 KNN k近邻法&#xff08;k-nearest neighbor&#xff0c;k-NN&#xff09;是一种基本分类与回归方法。 k近邻法的输入为实例的特征向量对应于特征空间的点&#xff1b;输出为实例的类别&…...

SpringBoot整合RabbitMQ

SpringBoot整合RabbitMQ&#xff0c;生产者 &#xff08;1&#xff09;创建maven项目 &#xff08;2&#xff09;引入依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><versi…...

Hive---安装教程

Hive安装教程 Hive属于Hadoop生态圈&#xff0c;所以Hive必须运行在Hadoop上 文章目录Hive安装教程上传安装包解压并且更名修改 /etc/profile创建hive-site.xml将mysql的jar包放入Hive库中开启刷新配置文件hadoop开启mysql初始化启动hive上传安装包 将安装包上传到/opt/insta…...

MySQL作业四

学生表&#xff1a;Student (Sno, Sname, Ssex , Sage, Sdept) 学号&#xff0c;姓名&#xff0c;性别&#xff0c;年龄&#xff0c;所在系 Sno为主键 课程表&#xff1a;Course (Cno, Cname,) 课程号&#xff0c;课程名 Cno为主键 学生选课表&#xff1a;SC (Sno, Cno, Score)…...

云原生安全检测器 Narrows(CNSI)的部署和使用

近日&#xff0c; 云原生安全检测器 Narrows&#xff08;Cloud Native Security Inspector&#xff0c;简称CNSI&#xff09;发布了0.2.0版本。 &#xff08;https://github.com/vmware-tanzu/cloud-native-security-inspector&#xff09; 此项目旨在对K8s集群中的工作负载进…...

【并发编程】【3】Java线程 创建线程与线程运行

并发编程 3.Java线程 本章内容 创建和运行线程 查看线程 线程 API 线程状态 3.1 创建和运行线程 方法一&#xff0c;直接使用 Thread // 创建线程对象 Thread t new Thread() {public void run() {// 要执行的任务} }; // 启动线程 t.start();例如&#xff1a; // 构…...

Ambire 最新消息——2023 年 1 月

大家好&#xff0c;这里是我们在过去几周所做的一切的快速回顾。 发展 整个钱包的交易模拟和余额预测 我们推出了一项真正改变加密钱包 UX 游戏规则的功能&#xff1a;Ambire 现在向用户显示他们的钱包余额将如何更新&#xff0c;甚至在签署交易之前。 这项新功能可以分解为 Am…...

【kubeflow | 镜像源的解决方法——脚本】

20230214 方式一&#xff1a;获取所有镜像列表&#xff0c;自行外网拉取下载 获取KF所需镜像列表脚本 Offical docs for getting all kubeflow images curl https://gist.githubusercontent.com/Jason-CKY/7d7056ce261c6d606585f05218230037/raw/5c27297efdf6424cd9679b9f7…...

function calling convention(函数调用约定)

函数调用约定 函数调用约定,是指当一个函数被调用时,函数的参数会被传递给被调用的函数和返回值会被返回给调用函数。函数的调用约定就是描述参数是怎么传递和由谁平衡...

errgroup 原理简析

golang.org/x/sync/errgroup errgroup提供了一组并行任务中错误采集的方案。 先看注释 Package errgroup provides synchronization, error propagation, and Context cancelation for groups of goroutines working on subtasks of a common task. Group 结构体 // A Gro…...

Centos7.6 下 Docker 安装

Docker的自动化安装 官方的一键安装方式&#xff1a; curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun 国内 daocloud一键安装命令&#xff1a; curl -sSL https://get.daocloud.io/docker | sh Docker手动安装 手动安装Docker分三步&#xff1a;卸…...

C++11--lambda表达式

目录 lambda表达式的概念 lambda表达式语法 lambda表达式的书写格式 捕捉列表 参数列表 mutable 返回值类型 函数体 lambda表达式交换两个数 函数对象与lambda表达式 lambda表达式的概念 lambda表达式是一个匿名函数 它能让代码更加地简洁 提高了代码可读性 首先定义…...

四【Spring框架】

目录一 Spring概述二 .Spring 的体系结构三 Spring的开发环境3.1 配置pom.xml文件四 项目案例&#xff1a;4.1 创建实体类4.2 在pom.xml中引入依赖4.3 配置Spring-config.xml文件4.4 Test✅作者简介&#xff1a;Java-小白后端开发者 &#x1f96d;公认外号&#xff1a;球场上的…...

树与二叉树 总复习

一、树的定义 树是一个有n个&#xff08;n>0&#xff09;结点的有限集合。 如果n0&#xff0c;称为空树&#xff1b; 如果n>0&#xff0c;称为非空树&#xff0c;有且仅有一个特定的称为根Root的结点&#xff08;无直接前驱&#xff09; 如果n>1,除了根节点外&…...

window10安装MySQL数据库

准备好软件MySql的下载参考&#xff1a;(1137条消息) mysql下载与安装过程_weixin_40396510的博客-CSDN博客_mysql数据库下载安装(1137条消息) 安装MySQL的常见问题_二木成林的博客-CSDN博客_sc不是内部或外部命令,也不是可运行的程序解压要C盘&#xff08;自定义&#xff0c;本…...

羊了个羊游戏开发教程3:卡牌拾取和消除

本文首发于微信公众号&#xff1a; 小蚂蚁教你做游戏。欢迎关注领取更多学习做游戏的原创教程资料&#xff0c;每天学点儿游戏开发知识。嗨&#xff01;大家好&#xff0c;我是小蚂蚁。终于要写第三篇教程了&#xff0c;中间拖的时间有点儿长&#xff0c;以至于我的好几位学员等…...

SHA1详解

目录 一、介绍 二、与MD5的区别 1、对强行攻击的安全性 2、对密码分析的安全性 3、速度 三、应用 1、文件指纹 2、Git中标识对象 四、算法原理 1、填充消息 2、消息处理 3、数据运算 &#xff08;1&#xff09;链接变量 &#xff08;2&#xff09;步函数 一、介绍…...

Go并发介绍及其使用

1. goroutine Go语言通过go关键字来启动一个goroutine。注意&#xff1a;go关键字后面必须跟一个函数&#xff0c;不能是语句或者其他东西&#xff0c;函数的返回值被忽略。 goroutine有如下特性&#xff1a; go的执行是非阻塞的&#xff0c;不会等待。go后面的函数的返回值…...

小米手机屏幕解锁技巧精选

手机锁是一种保护存储的用户数据和信息的方法。存储在锁定手机中的所有信息比任何人都可以访问的手机安全得多。但有时&#xff0c;如果用户忘记了这些屏幕锁定&#xff0c;可能会造成麻烦。在此博客中&#xff0c;我们将帮助用户了解如何解锁小米手机。 什么时候需要解锁小米手…...

朋友做的网站图片不显示/贵阳网站建设推广

一&#xff1a;标准的JavaWeb工程的工程结构 一个JavaWeb应用&#xff0c;需要有一个目录结构&#xff0c;tomcat才能够对其进行运行&#xff1b; ● tomcat安装目录/webapps/&#xff1a;所有的web应用应该存放在这个目录&#xff1b;在/webapps/目录下&#xff0c;所有的工…...

一个人做公司管理网站/seo智能优化公司

一、标题title 在浏览器标签处显示的内容&#xff0c;写在html的head部分 <head><title>网页标题</title> </head>二、网页简述description 对网页的一个简单概述&#xff0c;写在html的head部分 <head><meta name"description"…...

做网站的外包公司上班好不好/seochan是什么意思

背景: 因为移动端APP和Msite手机注册发送短信验证码没有添加图片验证码功能。公司的短信接口被恶意刷取。所以我们就觉得在移动端添加一个图片验证码功能。分享一下大体实现方式思路。PS demo是自己写的。跟公司代码还是有很大差距的。 一. 图片验证码第一版    1. 建立图片…...

wordpress当前文章所属分类/互联网营销师证书有用吗

“ 阅读文本大概需要 5 分钟 此文首发于「Python知识圈」公众号&#xff0c;欢迎大家去关注。 周末&#xff0c;打开手机听听音乐放松下&#xff0c;发现手机里的音乐好久没换了&#xff0c;想听点其他歌却不知道换什么歌&#xff0c;你们有没有遇到这样的听歌慌&#xff0c…...

本地主机做网站/百度一下官网首页

壹 如今 一年不见&#xff0c;你还好么 听说这一年 你也参加了这样那样的会议 你说 没有干货&#xff0c;听得困了 结果打盹十分钟&#xff0c;醒来世界都变了 有时感觉台上广告讲的不错 内心有点复杂 想问问这时的你 是不是也会想我 想起我们曾经纯粹干货交流 那质朴而又…...

wordpress 乱码/推广软文300字范文

硬件系统设计硬件平台基于ARM920T的处理器AT91RM9200&#xff0c;该处理器不仅有丰富的片上资源和标准接口&#xff0c;而且有低功耗、低成本、高性能、支持多种主要的嵌入式操作系统等特点&#xff0c;其采用5级整数流水线结构&#xff0c;性能高达200此方案的硬件系统结构设计…...