| 
									
										
										
										
											2024-04-24 10:25:44 +08:00
										 |  |  | #pragma once
 | 
					
						
							|  |  |  | #include "Singleton.h"
 | 
					
						
							|  |  |  | #include "l_squirrel.h"
 | 
					
						
							|  |  |  | #include <iostream>
 | 
					
						
							|  |  |  | #include <asio.hpp>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern HSQUIRRELVM v; | 
					
						
							|  |  |  | extern std::recursive_mutex SqMtx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace asio; | 
					
						
							|  |  |  | using asio::ip::tcp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Client | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     asio::io_context io_context; | 
					
						
							|  |  |  |     tcp::resolver resolver; | 
					
						
							|  |  |  |     tcp::socket socket; | 
					
						
							|  |  |  |     tcp::resolver::results_type endpoint; | 
					
						
							|  |  |  |     std::array<char, 8192> buffer; | 
					
						
							|  |  |  |     std::array<char, 8192000> PackData; | 
					
						
							|  |  |  |     std::size_t writeDataSize = 0; | 
					
						
							|  |  |  |     std::size_t receivedDataSize = 0; | 
					
						
							|  |  |  |     std::size_t TestCode = 0; | 
					
						
							|  |  |  |     std::string Ip = "192.168.200.27"; | 
					
						
							|  |  |  |     // std::string Ip = "127.0.0.1";
 | 
					
						
							|  |  |  |     std::string Port = "65109"; | 
					
						
							|  |  |  |     std::mutex PackMtx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     bool ConnectState = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2024-04-30 03:01:48 +08:00
										 |  |  |     Client(asio::io_context &io_context, std::string Ip, std::string Port) | 
					
						
							| 
									
										
										
										
											2024-04-24 10:25:44 +08:00
										 |  |  |         : resolver(io_context), | 
					
						
							|  |  |  |           socket(io_context) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         endpoint = resolver.resolve(Ip, Port); | 
					
						
							|  |  |  |         PackData.fill(0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void start() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         async_connect(socket, endpoint, [this](const asio::error_code &error, const tcp::endpoint &endpoint) | 
					
						
							|  |  |  |                       { | 
					
						
							|  |  |  |         if (!error) { | 
					
						
							|  |  |  |             ConnectState = true; | 
					
						
							|  |  |  |             read(); | 
					
						
							|  |  |  |             std::lock_guard<std::recursive_mutex> lock(SqMtx); | 
					
						
							|  |  |  |             SQInteger top = sq_gettop(v); // saves the stack size before the call
 | 
					
						
							|  |  |  |             sq_pushroottable(v);          // pushes the global table
 | 
					
						
							|  |  |  |             sq_pushstring(v, _SC("OnGatewaySocketConnect"), -1); | 
					
						
							|  |  |  |             if (SQ_SUCCEEDED(sq_get(v, -2))) | 
					
						
							|  |  |  |             {                        // gets the field 'foo' from the global table
 | 
					
						
							|  |  |  |                 sq_pushroottable(v); // push the 'this' (in this case is the global table)
 | 
					
						
							|  |  |  |                 sq_call(v, 1, SQFalse, SQTrue); // calls the function
 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             sq_settop(v, top); // restores the original stack size
 | 
					
						
							|  |  |  |             io_context.poll(); // 处理一次事件循环,避免主线程阻塞
 | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             std::cerr << "Error connecting to server: " << error.message() << std::endl; | 
					
						
							|  |  |  |         } }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void read() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         socket.async_read_some(asio::buffer(buffer), [this](const asio::error_code &error, std::size_t bytes_transferred) | 
					
						
							|  |  |  |                                { | 
					
						
							|  |  |  |         if (!error) { | 
					
						
							|  |  |  |             PackMtx.lock(); | 
					
						
							|  |  |  |             for (std::size_t i = 0; i < bytes_transferred; ++i) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 PackData[writeDataSize + i] = buffer[i]; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             writeDataSize += bytes_transferred; | 
					
						
							|  |  |  |             PackMtx.unlock(); | 
					
						
							|  |  |  |             read(); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             std::cerr << "Error reading data: " << error.message() << std::endl; | 
					
						
							|  |  |  |             reconnect(); | 
					
						
							|  |  |  |         } }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void reconnect() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         ConnectState = false; | 
					
						
							|  |  |  |         std::cout << "服务器断开连接,尝试重连." << std::endl; | 
					
						
							|  |  |  |         // 执行重连操作
 | 
					
						
							|  |  |  |         // 关闭当前连接
 | 
					
						
							|  |  |  |         socket.close(); | 
					
						
							|  |  |  |         // 重新解析端点
 | 
					
						
							|  |  |  |         endpoint = resolver.resolve(Ip, Port); | 
					
						
							|  |  |  |         // 重新连接
 | 
					
						
							|  |  |  |         async_connect(socket, endpoint, [this](const asio::error_code &error, const tcp::endpoint &endpoint) | 
					
						
							|  |  |  |                       { | 
					
						
							|  |  |  |             if (!error) { | 
					
						
							|  |  |  |                 ConnectState = true; | 
					
						
							|  |  |  |                 std::lock_guard<std::recursive_mutex> lock(SqMtx); | 
					
						
							|  |  |  |                 SQInteger top = sq_gettop(v); // saves the stack size before the call
 | 
					
						
							|  |  |  |                 sq_pushroottable(v);          // pushes the global table
 | 
					
						
							|  |  |  |                 sq_pushstring(v, _SC("OnGatewaySocketConnect"), -1); | 
					
						
							|  |  |  |                 if (SQ_SUCCEEDED(sq_get(v, -2))) | 
					
						
							|  |  |  |                 {                                   // gets the field 'foo' from the global table
 | 
					
						
							|  |  |  |                     sq_pushroottable(v);            // push the 'this' (in this case is the global table)
 | 
					
						
							|  |  |  |                     sq_call(v, 1, SQFalse, SQTrue); // calls the function
 | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 sq_settop(v, top); // restores the original stack size
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 read(); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 std::cerr << "Error reconnecting to server: " << error.message() << std::endl; | 
					
						
							|  |  |  |                 // 可以在此处添加重连失败的处理逻辑
 | 
					
						
							|  |  |  |                 reconnect(); | 
					
						
							|  |  |  |             } }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void send(unsigned char *message, int Length) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         async_write(socket, asio::buffer(message, Length), [this](const asio::error_code &error, std::size_t bytes_transferred) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |         if (!error) { | 
					
						
							|  |  |  |             // std::cout << "Message sent" << std::endl;
 | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             std::cerr << "Error sending message: " << error.message() << std::endl; | 
					
						
							|  |  |  |         } }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void PackLogic() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // 如果包长度不够直接返回
 | 
					
						
							|  |  |  |         if (PackData.size() < 4) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         // 如果里面已经读了超过一半的大小了
 | 
					
						
							|  |  |  |         if (writeDataSize >= 40960) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             PackMtx.lock(); | 
					
						
							|  |  |  |             // 删除前XX个元素
 | 
					
						
							|  |  |  |             std::copy(PackData.begin() + receivedDataSize, PackData.end(), PackData.begin()); | 
					
						
							|  |  |  |             // 将最后16个元素设置为0
 | 
					
						
							|  |  |  |             std::fill(PackData.end() - receivedDataSize, PackData.end(), 0); | 
					
						
							|  |  |  |             // 写的大小重置
 | 
					
						
							|  |  |  |             writeDataSize -= receivedDataSize; | 
					
						
							|  |  |  |             // 读的大小重置
 | 
					
						
							|  |  |  |             receivedDataSize = 0; | 
					
						
							|  |  |  |             PackMtx.unlock(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         unsigned char *Count = new unsigned char[4]; | 
					
						
							|  |  |  |         std::copy(PackData.begin() + receivedDataSize, PackData.begin() + 4 + receivedDataSize, Count); | 
					
						
							|  |  |  |         int PackSize = ByteLittleToInt(Count); | 
					
						
							|  |  |  |         delete[] Count; | 
					
						
							|  |  |  |         // 如果长度不够直接返回
 | 
					
						
							|  |  |  |         if (PackSize <= 0) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         char *StrBuffer = new char[PackSize + 1]; | 
					
						
							|  |  |  |         std::copy(PackData.begin() + 4 + receivedDataSize, PackData.begin() + 4 + PackSize + receivedDataSize, StrBuffer); | 
					
						
							|  |  |  |         StrBuffer[PackSize] = '\0'; | 
					
						
							|  |  |  |         // 这次读了多少
 | 
					
						
							|  |  |  |         receivedDataSize += (4 + PackSize); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         std::string Str = StrBuffer; | 
					
						
							|  |  |  |         delete[] StrBuffer; | 
					
						
							|  |  |  |         // std::cout << "包大小:  " << PackSize << std::endl;
 | 
					
						
							|  |  |  |         // std::cout << "包内容:  " << Str << std::endl;
 | 
					
						
							|  |  |  |         // std::cout << "收到了第:  " << TestCode << "个包" << std::endl;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         std::lock_guard<std::recursive_mutex> lock(SqMtx); | 
					
						
							|  |  |  |         SQInteger top = sq_gettop(v); // saves the stack size before the call
 | 
					
						
							|  |  |  |         sq_pushroottable(v);          // pushes the global table
 | 
					
						
							|  |  |  |         sq_pushstring(v, _SC("OnGatewaySocketMsg"), -1); | 
					
						
							|  |  |  |         if (SQ_SUCCEEDED(sq_get(v, -2))) | 
					
						
							|  |  |  |         {                        // gets the field 'foo' from the global table
 | 
					
						
							|  |  |  |             sq_pushroottable(v); // push the 'this' (in this case is the global table)
 | 
					
						
							|  |  |  |             sq_pushstring(v, Str.c_str(), -1); | 
					
						
							|  |  |  |             sq_call(v, 2, SQFalse, SQTrue); // calls the function
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         sq_settop(v, top); // restores the original stack size
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TestCode++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static int ByteLittleToInt(unsigned char *Count) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int int1 = Count[0] & 0xff; | 
					
						
							|  |  |  |         int int2 = (Count[1] & 0xff) << 8; | 
					
						
							|  |  |  |         int int3 = (Count[2] & 0xff) << 16; | 
					
						
							|  |  |  |         int int4 = (Count[3] & 0xff) << 24; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return int1 | int2 | int3 | int4; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class l_socket | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     l_socket() {}                                   // private constructor to prevent instantiation
 | 
					
						
							|  |  |  |     l_socket(const l_socket &) = delete;            // disable copy constructor
 | 
					
						
							|  |  |  |     l_socket &operator=(const l_socket &) = delete; // disable assignment operator
 | 
					
						
							|  |  |  |     Client *ClientObj; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     bool InitState = false; | 
					
						
							|  |  |  |     static l_socket &getInstance() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         static l_socket instance; | 
					
						
							|  |  |  |         return instance; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void InitSqr(); | 
					
						
							|  |  |  |     void InitPackLogic(); | 
					
						
							| 
									
										
										
										
											2024-04-30 03:01:48 +08:00
										 |  |  |     void Init(std::string Ip, std::string Port); | 
					
						
							| 
									
										
										
										
											2024-04-24 10:25:44 +08:00
										 |  |  |     void Send(const SQChar *Pck); | 
					
						
							|  |  |  |     void Logic(); | 
					
						
							|  |  |  |     void IntToByteLittle(unsigned char *b, int Count); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | }; |