ESP8266 TCP客户端代码(自动连接,断开识别)
程序员文章站
2024-03-23 09:40:34
...
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