ESP8266 TCP客户端代码(自动连接,断开识别)

news/2024/5/17 15:30:35 标签: 物联网, ESP8266, TCP

user_socket.c

#include "user_socket.h"



//===================================================================
//							变量定义
//===================================================================
int tcp_fd = -1;




/********************************************************************
 *@brief	发送TCP数据
 *@param[in] buffer
 *@param[in] size
 *@return	 <0失败	成功时返回已发送的长度
 *******************************************************************/
int user_socket_tcp_send(const void *buffer, size_t size)
{
	if(tcp_fd < 0 || buffer == NULL || size <= 0)
	{
		return -1;
	}

	return send(tcp_fd,buffer,size,0);
}


/********************************************************************
 *@brief	TCP连接
 *@param[in] none
 *@return	 <0失败	成功时返回fd
 *******************************************************************/
int user_socket_tcp_connect(void)
{
	int fd;
	int tmp;
	struct sockaddr_in addr;
	memset((char*)&addr,0,sizeof(addr));

	addr.sin_family 	 = AF_INET;
	addr.sin_port 		 = htons(USER_TCP_PORT);
	addr.sin_addr.s_addr = inet_addr(USER_TCP_IP);

	fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd < 0)
	{
		printf("tcp socket fail\n");
		return -1;
	}

	//开启keepalive属性
	tmp = 1;
	if(setsockopt(fd, SOL_SOCKET,SO_KEEPALIVE,&tmp,sizeof(tmp)) < 0)
	{
		printf("tcp set SO_KEEPALIVE fail\n");
	}

	//如该连接在10秒内没有任何数据往来,则进行探测
	tmp = 10;
	if(setsockopt(fd, IPPROTO_TCP,TCP_KEEPIDLE,&tmp,sizeof(tmp))<0)
	{
		printf("tcp set TCP_KEEPIDLE fail\n");
	}

	//探测时发包的时间间隔为2秒
	tmp = 2;
	if(setsockopt(fd, IPPROTO_TCP,TCP_KEEPINTVL,&tmp,sizeof(tmp))<0)
	{
		printf("tcp set TCP_KEEPINTVL fail\n");
	}

	//探测尝试的次数.如果第1次探测包就收到响应了,则后几次的不再发
	tmp = 3;
	if(setsockopt(fd, IPPROTO_TCP,TCP_KEEPCNT,&tmp,sizeof(tmp))<0)
	{
		printf("tcp set TCP_KEEPCNT fail\n");
	}

	//开始连接tcp
	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
	{
		close(fd);
		printf("tcp connect fail\n");
		return -1;
	}

	printf("tcp connect ok!\n");

	return fd;
}



/********************************************************************
 *@brief	TCP任务
 *@param[in] pvParameters
 *@return	 none
 *******************************************************************/
static void user_socket_tcp_task(void *pvParameters)
{
	printf("%s\n",__func__);

	//申请TCP接收buff内存
	uint8_t *tcp_rx_buff = NULL;
	if((tcp_rx_buff = (uint8_t*)os_malloc(USER_TCP_RX_BUFF_MAX)) == NULL)
	{
		printf("failed to allocate memory\r\n");
		goto	user_socket_tcp_task_exit;
	}


	tcp_fd = -1;
	int    ufd,maxfd;
	fd_set rset;
	struct timeval 		timeout;
	struct sockaddr_in  addr;
	memset((char*)&addr,0,sizeof(addr));

	addr.sin_family 	 = AF_INET;
	addr.sin_port   	 = htons(10000);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);

	ufd = socket(AF_INET, SOCK_DGRAM, 0);

	if(ufd < 0)
	{
		printf("create udp socket fail\n");
	}

	bind(ufd, (struct sockaddr*)&addr, sizeof(addr));

	maxfd = ufd;

	//清空socket集合
	FD_ZERO(&rset);


	while(1)
	{
		//wifi没有连接成功,或者还没有获取到IP
		if(wifi_station_get_connect_status() != STATION_GOT_IP)
		{
			vTaskDelay(100/portTICK_RATE_MS);
			continue;
		}

		//是否socket没有连接
		if(tcp_fd < 0)
		{
			//尝试连接socket
			if((tcp_fd = user_socket_tcp_connect()) < 0)
			{
				vTaskDelay(500/portTICK_RATE_MS);
				continue;
			}
		}

		maxfd = ufd;
		if(maxfd < tcp_fd)
		{
			maxfd = tcp_fd;
		}

		//清空socket集合
		FD_ZERO(&rset);

		if(tcp_fd >= 0)
		{
			//加入已连接的socket到集合
			FD_SET(tcp_fd,&rset);
		}

		FD_SET(ufd,&rset);

		timeout.tv_sec  = 3;	//秒
		timeout.tv_usec = 0;	//微秒
		//在此函数最大等待timeout.tv_sec秒,如果有收到数据就立即退出此函数。
		if(select(maxfd+1, &rset, NULL, NULL, &timeout) <= 0)
		{
			continue;
		}


		//检查tcp_fd是否在这个集合里面
		if (FD_ISSET(tcp_fd, &rset))
		{
			int read_length;

			//TCP接收数据处理
			if((read_length = recv(tcp_fd,tcp_rx_buff,USER_TCP_RX_BUFF_MAX,0)) > 0)
			{
				printf("fd read_buff data bytes:%d\r\n",read_length);
				USER_LOG_HEXDUMP(tcp_rx_buff,read_length);
			}
			else
			{
				close(tcp_fd);
				tcp_fd = -1;

				printf("tcp disconnectd!\r\n");
			}
		}
		//检查ufd是否在这个集合里面
		else if(FD_ISSET(ufd,&rset))
		{
			int alen = sizeof(struct sockaddr_in);

			int read_length;
			if((read_length=recvfrom(ufd,tcp_rx_buff,USER_TCP_RX_BUFF_MAX,0,(struct sockaddr*)&addr,(socklen_t*)&alen)) > 0)
			{
				printf("ufd read_buff data bytes:%d\r\n",read_length);
				USER_LOG_HEXDUMP(tcp_rx_buff,read_length);
			}
		}
	}

user_socket_tcp_task_exit:
	if(tcp_rx_buff != NULL)  aos_free(tcp_rx_buff);

	vTaskDelete(NULL);
}





/********************************************************************
 *@brief	 tcp初始化
 *@param[in] none
 *@return	 none
 *******************************************************************/
void user_socket_tcp_init(void)
{
    xTaskCreate(user_socket_tcp_task, "", 256, NULL, 4, NULL);
}










user_socket.h

#ifndef __USER_SOCKET_H__
#define __USER_SOCKET_H__

#include "esp_common.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "lwip/sockets.h"


//===================================================================
//							常量定义
//===================================================================
#define	USER_TCP_IP					"192.168.46.108"
#define	USER_TCP_PORT				8080
#define USER_TCP_RX_BUFF_MAX		256





//===================================================================
//							函数声明
//===================================================================
static void user_socket_tcp_task(void *pvParameters);
int user_socket_tcp_send(const void *buffer, size_t size);
void user_socket_tcp_init(void);
#endif

使用说明:

        1、在user_init函数中调用user_socket_tcp_init创建tcp任务

        2、WIFI连接成功之后,会自动进行TCP连接,tcp连接成功时打印 tcp connect ok!。tcp断开连接时打印tcp disconnectd!。收到tcp数据时打印fd read_buff data bytes。

        3、’用户发送tcp数据时调用user_socket_tcp_send


http://www.niftyadmin.cn/n/830759.html

相关文章

FreeRTOS可变数据长度的队列

背景&#xff1a;使用xQueueCreate创建队列时&#xff0c;我们发现只有两个参数&#xff0c;队列深度和单元长度&#xff0c;单元长度为该队列每组数据的最大长度&#xff0c;由于实际应用中&#xff0c;可能每个消息的数据长度都不一样&#xff0c;因此都设同样的长度会造成内…

阿里云对象存储上传文件

1、登录阿里云官网 阿里云-上云就上阿里云 2、点击产品&#xff0c;找到对象存储OSS&#xff0c;点击进去 3、如果首次使用&#xff0c;下面可能显示立即购买或者折扣套餐&#xff0c;点击进去购买。如果已经购买&#xff0c;则跳到第5步 4、使用默认选项即可&#xff0c;购买…

ESP8266/ESP32 SDK3 OTA升级

1、本示例适合于ESP8266和ESP32的OTA升级&#xff0c;使用官方的RTOS SDK3的框架编程&#xff0c;用户只要给出URL&#xff0c;代码自动解析出域名、IP、端口、文件路径等信息&#xff0c;然后通过HTTP请求下载固件。 2、本人测试固件放到阿里云对象存储OSS中&#xff0c;可以参…

java中栈(stack)和堆(heap)的区别

1.Java中对象都是分配在heap(堆)中。从heap中分配内存所消耗的时间远远大于从stack产生存储空间所需的时间。 每个应用程序运行时&#xff0c;都有属于自己的一段内存空间&#xff0c;用于存放临时变量、参数传递、函数调用时的PC值的保存。这叫stack。 所有的应用可以从一个系…

Windows下使用阿里云服务器远程编辑、编译ESP8266程序

1、前提条件&#xff1a;已购买阿里云服务器&#xff0c;本文使用的服务器信息&#xff1a;2核/2GiB、Ubuntu 18.04 64位、云盘空间40G 2、使用MobaXterm连接阿里云服务器 打开MobaXterm&#xff0c;点击Session ①点击SSH ②输入服务器IP地址&#xff0c;该地址为服务器的公…

java实现的一些二叉树算法

二叉堆 完全二叉树 二叉堆满足二个特性&#xff1a; 1&#xff0e;父结点的键值总是大于或等于&#xff08;小于或等于&#xff09;任何一个子节点的键值。 2&#xff0e;每个结点的左子树和右子树都是一个二叉堆&#xff08;都是最大堆或最小堆&#xff09;。 当父结点的键…

时间复杂度O(N)

我们假设计算机运行一行基础代码需要执行一次运算。 int aFunc(void) {printf("Hello, World!\n"); // 需要执行 1 次return 0; // 需要执行 1 次 }那么上面这个方法需要执行 2 次运算 int aFunc(int n) {for(int i 0; i<n; i) { // 需要执…

ubuntu 搭建ESP32开发环境

本文参考官方文档https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/get-started/index.html#get-started-get-esp-idfhttps://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/get-started/index.html#get-started-get-esp-idfhttps://docs.espressif…