/* * udp_client.cpp * * Created on: 2023年4月17日 * Author: m */ #include "udp_client.h" #include #include #include #include "entry/EasyuiContext.h" #include "utils/Log.h" #include "utils/ByteUtil.h" #include "base/os.hpp" #include "base/strings.hpp" #include "net/NetManager.h" #include "service/BusinessConfig.h" #include "core/utilities.h" #define ETHERNETMANAGER NETMANAGER->getEthernetManager() #define WIFIMANAGER NETMANAGER->getWifiManager() #define DISCOVERY_PORT 8031 #define DISCOVERY_TIMEOUT 10 #define CONNECTION_TIMEOUT 120 void udpHandleMsg(byte* msg); UdpClient::UdpClient() { busy_ = false; } UdpClient::~UdpClient() { } UdpClient* UdpClient::instance() { static UdpClient singleton; return &singleton; } static net::Conn* discover_conn; static net::Conn* conn; void UdpClient::sendMsg(const char* msg){ instance()->internalSendMsg(msg, conn); } void UdpClient::sendMsg(const char* msg, net::Conn* _conn){ instance()->internalSendMsg(msg, conn); } void UdpClient::internalSendMsg(const char* msg, net::Conn* _conn) { if (busy_) { LOGD("udp client is busy"); return; } busy_ = true; std::string endDelimiter = "#END#"; std::string msgStr = msg + endDelimiter; const char* sendMsg = msgStr.c_str(); if (_conn){ _conn->Write((byte*)(sendMsg), strlen(sendMsg)); LOGD("udp sended msg : %s",sendMsg); } else { LOGD("udp disconnect"); } busy_ = false; } int ip4str_parse(const char *point, unsigned int result[4]) { for (int i = 0; i < 4; i++) { result[i] = 0; } char buf[18] = {0}, p = 0, q = 0; strcpy(buf, point); buf[strlen(point)] = '.'; for(int i = 0;i < 4; i++) { q = strchr(buf+p, '.') - buf; buf[q] = '\0'; result[i] = strtol(buf+p, NULL, 10); p = q + 1; } return 1; } char ip[64] = {0}; char mask[64] = {0}; char gateway[64] = {0}; char dns1[64] = {0}; char dns2[64] = {0}; std::string getBoasrAddress() { if (ETHERNETMANAGER->isConnected()) { if (ETHERNETMANAGER->isAutoMode()) { ETHERNETMANAGER->getConfigureInfo(ip, mask, gateway, dns1, dns2); } else { ETHERNETMANAGER->getStaticConfigureInfo(ip, mask, gateway, dns1, dns2); } } else if (WIFIMANAGER->isConnected()) { WIFIMANAGER->getConfigureInfo(ip, mask, gateway, dns1, dns2); // if (WIFIMANAGER->isAutoMode()) { // WIFIMANAGER->getConfigureInfo(ip, mask, gateway, dns1, dns2); // } // else { // WIFIMANAGER->getConfigureInfo(ip, mask, gateway, dns1, dns2); // } } unsigned int ipAdd[4]; unsigned int maskAdd[4]; ip4str_parse(ip, ipAdd); ip4str_parse(mask, maskAdd); int wilMask[4]; int startIpAdd[4],endIpAdd[4]; for (int i = 0; i < 4; i++) { wilMask[i] = 255 - maskAdd[i]; } for (int i = 0; i < 4; i++) { startIpAdd[i] = ipAdd[i] & maskAdd[i]; endIpAdd[i] = startIpAdd[i] + wilMask[i]; } std::string boasrAddress = std::to_string(endIpAdd[0]) + "." + std::to_string(endIpAdd[1]) + "." + std::to_string(endIpAdd[2]) + "." + std::to_string(endIpAdd[3]) + ":" + std::to_string(DISCOVERY_PORT); return boasrAddress; } class UdpClientThread: public Thread { private: enum State { STATE_DISCOVERING, // 正在广播探测 STATE_CONNECTED, // 已连接服务器 STATE_DISCONNECT, // 服务器断开 }; inline static std::string REQUEST = "REQUEST"; inline static std::string RESPONSE = "RESPONSE"; inline static std::string CONNECT = "CONNECT"; inline static std::string DISCONNECT = "DISCONNECT"; inline static std::string RECONNECT = "RECONNECT"; std::atomic current_state_{STATE_DISCOVERING}; std::string server_ip_; // 服务器地址缓存 std::string server_port_; // 服务器端口 bool send(net::Conn* _conn, const std::string msg) { // 构造消息字符串 std::string endDelimiter = "#END#"; std::string msgStr = msg + endDelimiter; const char* sendMsg = msgStr.data(); if (_conn){ _conn->Write((byte*)(sendMsg), strlen(sendMsg)); LOGD("向udp服务器发送消息 : %s", sendMsg); return true; } LOGD("udp disconnect"); return false; } void requestUdpServerIp(net::Conn* _conn) { Json::Value reqJson; reqJson["action"] = REQUEST; Json::FastWriter writer; const std::string req = writer.write(reqJson); send(_conn, req); } void sendDeviceMsg(net::Conn* _conn) { Json::Value reqJson; reqJson["action"] = CONNECT; reqJson["ip"] = ip; reqJson["mac"] = StoragePreferences::getString(STORE_MAC_ADDR, "0.0.0.0"); reqJson["gateway"] = gateway; reqJson["mask"] = mask; reqJson["version"] = versionCode + "_" + std::to_string(versionNo); reqJson["id"] = StoragePreferences::getInt(STORE_DEVICE_ID, 0); reqJson["partId"] = StoragePreferences::getString(STORE_PARTID, ""); reqJson["partName"] = StoragePreferences::getString(STORE_PARTNAME, ""); reqJson["frameName"] = StoragePreferences::getString(STORE_FRAME_FULL_NAME, ""); Json::FastWriter writer; const std::string req = writer.write(reqJson); send(_conn, req); } void handleDiscoveryState() { LOGD("进入广播探测状态"); using Clock = std::chrono::steady_clock; constexpr auto TIMEOUT = std::chrono::seconds(60); auto start_time = Clock::now(); // 设置一个默认地址 std::string boasrAddress = "172.28.100.100:" + std::to_string(DISCOVERY_PORT); if (ETHERNETMANAGER->isConnected() || WIFIMANAGER->isConnected()) { boasrAddress = getBoasrAddress(); } LOGD("UDP广播地址 ===> %s", boasrAddress.c_str()); discover_conn = net::Dial("udp", boasrAddress); if (!discover_conn) { current_state_ = STATE_DISCONNECT; LOGD("UDP广播连接失败,udp断开"); return; } requestUdpServerIp(discover_conn); byte buf[2048] = {0}; bool server_found = false; while (true) { auto elapsed = Clock::now() - start_time; if (elapsed >= TIMEOUT) break; //读取,超时1000毫秒 int n = discover_conn->Read(buf, sizeof(buf) - 1, 1000); if (n > 0) { Json::Value jsonData = ByteUtil::byteArrayToJson(buf, n); if (!jsonData.isNull() && jsonData.isMember("action")) { if (jsonData["action"] == RESPONSE) { server_ip_ = jsonData["ip"].asString(); server_port_ = jsonData["port"].asString(); LOGD("udp广播服务器的地址 ===> %s:%s", server_ip_.c_str(), server_port_.c_str()); server_found = true; break; } } } } //关闭连接 discover_conn->Close(); //释放内存 delete discover_conn; discover_conn = NULL; if (server_found) { current_state_ = STATE_CONNECTED; LOGD("收到udp服务器地址消息,切换到udp服务连接"); } else { current_state_ = STATE_DISCONNECT; LOGD("未收到udp服务器地址消息,断开udp"); } } void handleConnectedState() { LOGD("进入连接状态"); using namespace std::chrono; using Clock = steady_clock; std::string serverAddr = server_ip_ + ":" + server_port_; LOGD("定向连接udp服务器 ===> %s", serverAddr.c_str()); // 创建定向连接 conn = net::Dial("udp", serverAddr); if (!conn) { current_state_ = STATE_DISCONNECT; LOGD("UDP定向连接失败,udp断开"); return; } sendDeviceMsg(conn); constexpr auto TIMEOUT = std::chrono::seconds(120); constexpr auto HEARTBEAT = std::chrono::seconds(60); auto last_recv_time = Clock::now(); auto last_heartbeat = Clock::now(); auto connection_start = Clock::now(); // 通信循环 byte buffer[2048]; bool should_disconnect = false; while (!exitPending() && !should_disconnect) { auto time_since_last = steady_clock::now() - last_recv_time; if (time_since_last > TIMEOUT) { LOGD("连接超时(已等待%lld秒)", time_since_last.count()); should_disconnect = true; break; } auto time_since_heartbeat = steady_clock::now() - last_heartbeat; if (time_since_heartbeat >= HEARTBEAT) { const std::string msg = "0"; send(conn, msg); } // 动态计算本次读操作的超时时间(毫秒) auto remaining = duration_cast( TIMEOUT - time_since_last ); // 接收数据 int n = conn->Read(buffer, sizeof(buffer)-1, 1000); if (n > 0) { last_recv_time = Clock::now(); // 更新最后有效接收时间 const char* cstr = reinterpret_cast(buffer); std::string str = cstr; if (str == "1#END#"){ last_heartbeat = Clock::now(); continue; } LOGD("收到定向udp服务返回消息 ===> %s", cstr); Json::Value jsonData = ByteUtil::byteArrayToJson(buffer, n); if (!jsonData.isNull() && jsonData.isMember("action")) { if (jsonData["action"] == DISCONNECT) { // 退出线程 should_disconnect = true; current_state_ = STATE_DISCONNECT; break; } else if (jsonData["action"] == RECONNECT) { sendDeviceMsg(conn); } } // handleServerMessage(buffer); // 处理业务消息 } else if (n < 0 && n != net::E_TIMEOUT) { should_disconnect = true; current_state_ = STATE_DISCONNECT; break; // 发生错误 } } // 计算总连接时长 auto total_duration = steady_clock::now() - connection_start; LOGD("连接持续时间: %lld 秒", total_duration.count()); // 清理连接 conn->Close(); delete conn; conn = NULL; current_state_ = STATE_DISCONNECT; } public: /** * 线程创建成功后会调用该函数,可以在该函数中做一些初始化操作 * return true 继续线程 * false 退出线程 */ virtual bool readyToRun() { LOGD("Udp Thread 已经创建完成"); return true; } /** * 线程循环函数 * * return true 继续线程循环 * false 推出线程 */ virtual bool threadLoop() { LOGD("Udp 线程循环函数"); //检查是否有退出线程的请求,如果有,则返回false,立即退出线程 if (exitPending()) { LOGD("Udp exitPending"); return false; } switch (current_state_) { case STATE_DISCOVERING: handleDiscoveryState(); break; case STATE_CONNECTED: handleConnectedState(); break; case STATE_DISCONNECT: return false; break; } return true; } }; static UdpClientThread udp_thread; void UdpClient::startUdp(){ LOGD("运行Udp线程"); //调用线程类的run函数启动线程, 参数为线程名,可以任意指定。 if (!udp_thread.isRunning()) { udp_thread.run("udp thread"); } } void UdpClient::closeUdp() { bool result = udp_thread.isRunning(); if (result) { udp_thread.requestExitAndWait(); LOGD("my_thread已关闭"); } // my_thread.requestExit(); } bool UdpClient::busy() { return instance()->busy_; } bool UdpClient::connected() { return conn != NULL || discover_conn != NULL; }