/***************************************************************************** * @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; }