forked from gary/ems
2
0
Fork 0
sun_ems/ems_c/driver/drv_tcp_client.c

248 lines
7.5 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*****************************************************************************
* @copyright 2024-202, . POWER SUPPLY CO., LTD.
* @file drv_tcp.c
* @brief tcp驱动文件
* @author Gary
* @date 2024/08/30
* @remark 初修订
*****************************************************************************/
#include "drv_tcp_client.h"
/*****************************************************************************
* @brief 判断IP地址类型
* @param[in] ip地址
* @return 1: IPv4, 2: IPv6, 0: 无效地址
*****************************************************************************/
static int is_ip(const char *ip)
{
struct sockaddr_in sa;
if (inet_pton(AF_INET, ip, &(sa.sin_addr)) != 0)
{
return 1;
}
struct sockaddr_in6 sa6;
if (inet_pton(AF_INET6, ip, &(sa6.sin6_addr)) != 0)
{
return 2;
}
return 0;
}
/*****************************************************************************
* @brief 打印发送内容
* @param[in] str发送内容标题
* @param[in] data发送内容
* @param[in] len发送长度
* @return void
*****************************************************************************/
static void tcpPrintLog(const char *str, uint8_t *data, uint16_t len)
{
char sdata[512 * 2] = {0};
int pos = 0;
if ((uint8_t)getRtdbPointValue(rtdbType, kDev_Type_EMS, 0, kEms_TcpLog_Enable) == 1)
{
if (len > 0)
{
for (int i = 0; i < len; i++)
{
pos += snprintf(sdata + pos, sizeof(sdata) - pos, "%02x ", data[i]);
// 检查snprintf返回值确保写入成功并处理潜在错误
if (pos < 0 || pos >= sizeof(sdata))
{
KITPTF(LOG_DRIVER_EN, ERROR_EN, "tcpPrintLog: snprintf failed!");
break; // 停止继续处理
}
}
// 使用snprintf避免缓冲区溢出
pos += snprintf(sdata + pos, sizeof(sdata) - pos, "\n");
// 检查snprintf返回值确保写入成功并处理潜在错误
if (pos < 0 || pos >= sizeof(sdata))
{
KITPTF(LOG_DRIVER_EN, ERROR_EN, "tcpPrintLog: snprintf failed!");
}
}
KITPTF(LOG_DRIVER_EN, INFO_EN, "%s:%s", str, sdata);
KITLOG(LOG_DRIVER_EN, INFO_EN, "%s:%s", str, sdata);
}
}
/*****************************************************************************
* @brief 打开tcp驱动
* @param[in] p_tcp: tcp驱动结构体指针
* @return 0-成功 1-失败
*****************************************************************************/
int drvTcpOpen(tcp_client_lib_t *p_tcp)
{
// 判断IP地址类型1: IPv4, 2: IPv6, 0: 无效地址
int ip_type = is_ip(p_tcp->ip);
if (ip_type == 0)
{
KITLOG(LOG_DRIVER_EN, ERROR_EN, "无效 ip: %s", p_tcp->ip);
return 1;
}
p_tcp->socket_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in remote_in;
remote_in.sin_family = AF_INET;
remote_in.sin_port = htons(p_tcp->port);
if (inet_pton(AF_INET, p_tcp->ip, &remote_in.sin_addr) <= 0)
{
KITLOG(LOG_DRIVER_EN, ERROR_EN, "Invalid address or address not supported");
return 1;
}
if (p_tcp->socket_fd == -1)
{
KITLOG(LOG_DRIVER_EN, ERROR_EN, "socket 错误: %s(%d)\n", strerror(errno), errno);
return 1;
}
int ret = connect(p_tcp->socket_fd, (struct sockaddr *)&remote_in, sizeof(struct sockaddr_in));
if (ret == -1)
{
KITLOG(LOG_DRIVER_EN, ERROR_EN, "连接错误: %s(%d)\n", strerror(errno), errno);
KITPTF(LOG_DRIVER_EN, ERROR_EN, "连接错误: %s(%d)\n", strerror(errno), errno);
close(p_tcp->socket_fd);
return 1;
}
return 0; // 返回成功
}
/*****************************************************************************
* @brief 关闭tcp驱动
* @param[in] p_tcp: tcp驱动结构体指针
* @return 0-成功 1-失败
*****************************************************************************/
int drvTcpClose(tcp_client_lib_t *p_tcp)
{
if (p_tcp->socket_fd > 0)
{
close(p_tcp->socket_fd);
p_tcp->socket_fd = 0;
p_tcp->status = CONN_OFFLINE;
}
else
{
perror("Close fail!");
return 1;
}
return 0;
}
/*****************************************************************************
* @brief tcp驱动发送
* @param[in] p_tcp: tcp驱动结构体指针
* @return 0-成功 1-失败
*****************************************************************************/
int drvTcpSend(tcp_client_lib_t *p_tcp)
{
ssize_t ret = 0;
fd_set writefds;
struct timeval timeout;
timeout.tv_sec = 3; // 3秒超时
timeout.tv_usec = 0;
FD_ZERO(&writefds);
FD_SET(p_tcp->socket_fd, &writefds);
int retn = select(p_tcp->socket_fd + 1, NULL, &writefds, NULL, &timeout);
if (retn > 0 && FD_ISSET(p_tcp->socket_fd, &writefds))
{
goto sendpos;
}
else if (retn == 0)
{
KITLOG(LOG_DRIVER_EN, ERROR_EN, "Socket write timeout");
return 1;
}
else
{
// 发生错误
KITLOG(LOG_DRIVER_EN, ERROR_EN, "IP(%s) 发送错误! ret: %ld, errno: %s(%d)\n",
p_tcp->ip, ret, strerror(errno), errno);
// close(p_tcp->socket_fd); // 关闭 socket 协议层面去关闭,驱动层面不做处理,否则灵敏度过高
return 128;
}
sendpos:
while (ret < p_tcp->send_len)
{
ssize_t rc = send(p_tcp->socket_fd, p_tcp->send_buf + ret, p_tcp->send_len - ret, MSG_NOSIGNAL);
if (rc > 0)
{
ret += rc;
}
else
{
// 发生错误
if (rc < 0)
{
KITLOG(LOG_DRIVER_EN, ERROR_EN, "IP(%s) 发送错误! ret: %ld, errno: %s(%d)\n",
p_tcp->ip, ret, strerror(errno), errno);
KITPTF(LOG_DRIVER_EN, ERROR_EN, "IP(%s) 发送错误! ret: %ld, errno: %s(%d)\n",
p_tcp->ip, ret, strerror(errno), errno);
}
return 1;
}
}
tcpPrintLog("发送数据:", p_tcp->send_buf, p_tcp->send_len);
return 0;
}
/*****************************************************************************
* @brief tcp驱动接收
* @param[in] p_tcp: tcp驱动结构体指针
* @return 0-成功 1-失败
*****************************************************************************/
int drvTcpRecv(tcp_client_lib_t *p_tcp)
{
// 超时时间检测
if (0 != p_tcp->timeout)
{
fd_set set;
FD_ZERO(&set);
FD_SET(p_tcp->socket_fd, &set);
// 最大阻塞30s
if (p_tcp->timeout / 1000 > 30)
{
p_tcp->timeout = 30 * 1000;
}
struct timeval time_out = {p_tcp->timeout / 1000, (p_tcp->timeout % 1000) * 1000};
// 检测超时时间
int ret = select(p_tcp->socket_fd + 1, &set, NULL, NULL, &time_out);
if (0 == ret)
{
return -128;
}
else if (ret < 0)
{
return -1;
}
}
p_tcp->recv_len = recv(p_tcp->socket_fd, p_tcp->recv_buf, MAX_TCP_REV_LEN, 0);
if (p_tcp->recv_len < 0)
{
p_tcp->recv_len = 0;
return -1;
}
else if (0 == p_tcp->recv_len)
{
return -128;
}
else
{
tcpPrintLog("接收数据:", p_tcp->recv_buf, p_tcp->recv_len);
}
return 0;
}