udp_client.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /*
  2. * udp_client.cpp
  3. *
  4. * Created on: 2023年4月17日
  5. * Author: m
  6. */
  7. #include "udp_client.h"
  8. #include <system/Thread.h>
  9. #include <string>
  10. #include <chrono>
  11. #include "entry/EasyuiContext.h"
  12. #include "utils/Log.h"
  13. #include "utils/ByteUtil.h"
  14. #include "base/os.hpp"
  15. #include "base/strings.hpp"
  16. #include "net/NetManager.h"
  17. #include "service/BusinessConfig.h"
  18. #include "core/utilities.h"
  19. #define ETHERNETMANAGER NETMANAGER->getEthernetManager()
  20. #define WIFIMANAGER NETMANAGER->getWifiManager()
  21. #define DISCOVERY_PORT 8031
  22. #define DISCOVERY_TIMEOUT 10
  23. #define CONNECTION_TIMEOUT 120
  24. void udpHandleMsg(byte* msg);
  25. UdpClient::UdpClient() {
  26. busy_ = false;
  27. }
  28. UdpClient::~UdpClient() {
  29. }
  30. UdpClient* UdpClient::instance() {
  31. static UdpClient singleton;
  32. return &singleton;
  33. }
  34. static net::Conn* discover_conn;
  35. static net::Conn* conn;
  36. void UdpClient::sendMsg(const char* msg){
  37. instance()->internalSendMsg(msg, conn);
  38. }
  39. void UdpClient::sendMsg(const char* msg, net::Conn* _conn){
  40. instance()->internalSendMsg(msg, conn);
  41. }
  42. void UdpClient::internalSendMsg(const char* msg, net::Conn* _conn) {
  43. if (busy_) {
  44. LOGD("udp client is busy");
  45. return;
  46. }
  47. busy_ = true;
  48. std::string endDelimiter = "#END#";
  49. std::string msgStr = msg + endDelimiter;
  50. const char* sendMsg = msgStr.c_str();
  51. if (_conn){
  52. _conn->Write((byte*)(sendMsg), strlen(sendMsg));
  53. LOGD("udp sended msg : %s",sendMsg);
  54. } else {
  55. LOGD("udp disconnect");
  56. }
  57. busy_ = false;
  58. }
  59. int ip4str_parse(const char *point, unsigned int result[4]) {
  60. for (int i = 0; i < 4; i++) {
  61. result[i] = 0;
  62. }
  63. char buf[18] = {0}, p = 0, q = 0;
  64. strcpy(buf, point);
  65. buf[strlen(point)] = '.';
  66. for(int i = 0;i < 4; i++) {
  67. q = strchr(buf+p, '.') - buf;
  68. buf[q] = '\0';
  69. result[i] = strtol(buf+p, NULL, 10);
  70. p = q + 1;
  71. }
  72. return 1;
  73. }
  74. char ip[64] = {0};
  75. char mask[64] = {0};
  76. char gateway[64] = {0};
  77. char dns1[64] = {0};
  78. char dns2[64] = {0};
  79. std::string getBoasrAddress() {
  80. if (ETHERNETMANAGER->isConnected()) {
  81. if (ETHERNETMANAGER->isAutoMode()) {
  82. ETHERNETMANAGER->getConfigureInfo(ip, mask, gateway, dns1, dns2);
  83. } else {
  84. ETHERNETMANAGER->getStaticConfigureInfo(ip, mask, gateway, dns1, dns2);
  85. }
  86. }
  87. else if (WIFIMANAGER->isConnected()) {
  88. WIFIMANAGER->getConfigureInfo(ip, mask, gateway, dns1, dns2);
  89. // if (WIFIMANAGER->isAutoMode()) {
  90. // WIFIMANAGER->getConfigureInfo(ip, mask, gateway, dns1, dns2);
  91. // }
  92. // else {
  93. // WIFIMANAGER->getConfigureInfo(ip, mask, gateway, dns1, dns2);
  94. // }
  95. }
  96. unsigned int ipAdd[4];
  97. unsigned int maskAdd[4];
  98. ip4str_parse(ip, ipAdd);
  99. ip4str_parse(mask, maskAdd);
  100. int wilMask[4];
  101. int startIpAdd[4],endIpAdd[4];
  102. for (int i = 0; i < 4; i++) {
  103. wilMask[i] = 255 - maskAdd[i];
  104. }
  105. for (int i = 0; i < 4; i++) {
  106. startIpAdd[i] = ipAdd[i] & maskAdd[i];
  107. endIpAdd[i] = startIpAdd[i] + wilMask[i];
  108. }
  109. 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);
  110. return boasrAddress;
  111. }
  112. class UdpClientThread: public Thread {
  113. private:
  114. enum State {
  115. STATE_DISCOVERING, // 正在广播探测
  116. STATE_CONNECTED, // 已连接服务器
  117. STATE_DISCONNECT, // 服务器断开
  118. };
  119. inline static std::string REQUEST = "REQUEST";
  120. inline static std::string RESPONSE = "RESPONSE";
  121. inline static std::string CONNECT = "CONNECT";
  122. inline static std::string DISCONNECT = "DISCONNECT";
  123. inline static std::string RECONNECT = "RECONNECT";
  124. std::atomic<State> current_state_{STATE_DISCOVERING};
  125. std::string server_ip_; // 服务器地址缓存
  126. std::string server_port_; // 服务器端口
  127. bool send(net::Conn* _conn, const std::string msg) {
  128. // 构造消息字符串
  129. std::string endDelimiter = "#END#";
  130. std::string msgStr = msg + endDelimiter;
  131. const char* sendMsg = msgStr.data();
  132. if (_conn){
  133. _conn->Write((byte*)(sendMsg), strlen(sendMsg));
  134. LOGD("向udp服务器发送消息 : %s", sendMsg);
  135. return true;
  136. }
  137. LOGD("udp disconnect");
  138. return false;
  139. }
  140. void requestUdpServerIp(net::Conn* _conn) {
  141. Json::Value reqJson;
  142. reqJson["action"] = REQUEST;
  143. Json::FastWriter writer;
  144. const std::string req = writer.write(reqJson);
  145. send(_conn, req);
  146. }
  147. void sendDeviceMsg(net::Conn* _conn) {
  148. Json::Value reqJson;
  149. reqJson["action"] = CONNECT;
  150. reqJson["ip"] = ip;
  151. reqJson["mac"] = StoragePreferences::getString(STORE_MAC_ADDR, "0.0.0.0");
  152. reqJson["gateway"] = gateway;
  153. reqJson["mask"] = mask;
  154. reqJson["version"] = versionCode + "_" + std::to_string(versionNo);
  155. reqJson["id"] = StoragePreferences::getInt(STORE_DEVICE_ID, 0);
  156. reqJson["partId"] = StoragePreferences::getString(STORE_PARTID, "");
  157. reqJson["partName"] = StoragePreferences::getString(STORE_PARTNAME, "");
  158. reqJson["frameName"] = StoragePreferences::getString(STORE_FRAME_FULL_NAME, "");
  159. Json::FastWriter writer;
  160. const std::string req = writer.write(reqJson);
  161. send(_conn, req);
  162. }
  163. void handleDiscoveryState() {
  164. LOGD("进入广播探测状态");
  165. using Clock = std::chrono::steady_clock;
  166. constexpr auto TIMEOUT = std::chrono::seconds(60);
  167. auto start_time = Clock::now();
  168. // 设置一个默认地址
  169. std::string boasrAddress = "172.28.100.100:" + std::to_string(DISCOVERY_PORT);
  170. if (ETHERNETMANAGER->isConnected() || WIFIMANAGER->isConnected()) {
  171. boasrAddress = getBoasrAddress();
  172. }
  173. LOGD("UDP广播地址 ===> %s", boasrAddress.c_str());
  174. discover_conn = net::Dial("udp", boasrAddress);
  175. if (!discover_conn) {
  176. current_state_ = STATE_DISCONNECT;
  177. LOGD("UDP广播连接失败,udp断开");
  178. return;
  179. }
  180. requestUdpServerIp(discover_conn);
  181. byte buf[2048] = {0};
  182. bool server_found = false;
  183. while (true) {
  184. auto elapsed = Clock::now() - start_time;
  185. if (elapsed >= TIMEOUT) break;
  186. //读取,超时1000毫秒
  187. int n = discover_conn->Read(buf, sizeof(buf) - 1, 1000);
  188. if (n > 0) {
  189. Json::Value jsonData = ByteUtil::byteArrayToJson(buf, n);
  190. if (!jsonData.isNull() && jsonData.isMember("action")) {
  191. if (jsonData["action"] == RESPONSE) {
  192. server_ip_ = jsonData["ip"].asString();
  193. server_port_ = jsonData["port"].asString();
  194. LOGD("udp广播服务器的地址 ===> %s:%s", server_ip_.c_str(), server_port_.c_str());
  195. server_found = true;
  196. break;
  197. }
  198. }
  199. }
  200. }
  201. //关闭连接
  202. discover_conn->Close();
  203. //释放内存
  204. delete discover_conn;
  205. discover_conn = NULL;
  206. if (server_found) {
  207. current_state_ = STATE_CONNECTED;
  208. LOGD("收到udp服务器地址消息,切换到udp服务连接");
  209. }
  210. else {
  211. current_state_ = STATE_DISCONNECT;
  212. LOGD("未收到udp服务器地址消息,断开udp");
  213. }
  214. }
  215. void handleConnectedState() {
  216. LOGD("进入连接状态");
  217. using namespace std::chrono;
  218. using Clock = steady_clock;
  219. std::string serverAddr = server_ip_ + ":" + server_port_;
  220. LOGD("定向连接udp服务器 ===> %s", serverAddr.c_str());
  221. // 创建定向连接
  222. conn = net::Dial("udp", serverAddr);
  223. if (!conn) {
  224. current_state_ = STATE_DISCONNECT;
  225. LOGD("UDP定向连接失败,udp断开");
  226. return;
  227. }
  228. sendDeviceMsg(conn);
  229. constexpr auto TIMEOUT = std::chrono::seconds(120);
  230. constexpr auto HEARTBEAT = std::chrono::seconds(60);
  231. auto last_recv_time = Clock::now();
  232. auto last_heartbeat = Clock::now();
  233. auto connection_start = Clock::now();
  234. // 通信循环
  235. byte buffer[2048];
  236. bool should_disconnect = false;
  237. while (!exitPending() && !should_disconnect) {
  238. auto time_since_last = steady_clock::now() - last_recv_time;
  239. if (time_since_last > TIMEOUT) {
  240. LOGD("连接超时(已等待%lld秒)", time_since_last.count());
  241. should_disconnect = true;
  242. break;
  243. }
  244. auto time_since_heartbeat = steady_clock::now() - last_heartbeat;
  245. if (time_since_heartbeat >= HEARTBEAT) {
  246. const std::string msg = "0";
  247. send(conn, msg);
  248. }
  249. // 动态计算本次读操作的超时时间(毫秒)
  250. auto remaining = duration_cast<milliseconds>(
  251. TIMEOUT - time_since_last
  252. );
  253. // 接收数据
  254. int n = conn->Read(buffer, sizeof(buffer)-1, 1000);
  255. if (n > 0) {
  256. last_recv_time = Clock::now(); // 更新最后有效接收时间
  257. const char* cstr = reinterpret_cast<const char*>(buffer);
  258. std::string str = cstr;
  259. if (str == "1#END#"){
  260. last_heartbeat = Clock::now();
  261. continue;
  262. }
  263. LOGD("收到定向udp服务返回消息 ===> %s", cstr);
  264. Json::Value jsonData = ByteUtil::byteArrayToJson(buffer, n);
  265. if (!jsonData.isNull() && jsonData.isMember("action")) {
  266. if (jsonData["action"] == DISCONNECT) {
  267. // 退出线程
  268. should_disconnect = true;
  269. current_state_ = STATE_DISCONNECT;
  270. break;
  271. }
  272. else if (jsonData["action"] == RECONNECT) {
  273. sendDeviceMsg(conn);
  274. }
  275. }
  276. // handleServerMessage(buffer); // 处理业务消息
  277. } else if (n < 0 && n != net::E_TIMEOUT) {
  278. should_disconnect = true;
  279. current_state_ = STATE_DISCONNECT;
  280. break; // 发生错误
  281. }
  282. }
  283. // 计算总连接时长
  284. auto total_duration = steady_clock::now() - connection_start;
  285. LOGD("连接持续时间: %lld 秒", total_duration.count());
  286. // 清理连接
  287. conn->Close();
  288. delete conn;
  289. conn = NULL;
  290. current_state_ = STATE_DISCONNECT;
  291. }
  292. public:
  293. /**
  294. * 线程创建成功后会调用该函数,可以在该函数中做一些初始化操作
  295. * return true 继续线程
  296. * false 退出线程
  297. */
  298. virtual bool readyToRun() {
  299. LOGD("Udp Thread 已经创建完成");
  300. return true;
  301. }
  302. /**
  303. * 线程循环函数
  304. *
  305. * return true 继续线程循环
  306. * false 推出线程
  307. */
  308. virtual bool threadLoop() {
  309. LOGD("Udp 线程循环函数");
  310. //检查是否有退出线程的请求,如果有,则返回false,立即退出线程
  311. if (exitPending()) {
  312. LOGD("Udp exitPending");
  313. return false;
  314. }
  315. switch (current_state_) {
  316. case STATE_DISCOVERING:
  317. handleDiscoveryState();
  318. break;
  319. case STATE_CONNECTED:
  320. handleConnectedState();
  321. break;
  322. case STATE_DISCONNECT:
  323. return false;
  324. break;
  325. }
  326. return true;
  327. }
  328. };
  329. static UdpClientThread udp_thread;
  330. void UdpClient::startUdp(){
  331. LOGD("运行Udp线程");
  332. //调用线程类的run函数启动线程, 参数为线程名,可以任意指定。
  333. if (!udp_thread.isRunning()) {
  334. udp_thread.run("udp thread");
  335. }
  336. }
  337. void UdpClient::closeUdp() {
  338. bool result = udp_thread.isRunning();
  339. if (result) {
  340. udp_thread.requestExitAndWait();
  341. LOGD("my_thread已关闭");
  342. }
  343. // my_thread.requestExit();
  344. }
  345. bool UdpClient::busy() {
  346. return instance()->busy_;
  347. }
  348. bool UdpClient::connected() {
  349. return conn != NULL || discover_conn != NULL;
  350. }