229 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C++
		
	
	
	
| #pragma once
 | |
| #include "Singleton.h"
 | |
| #include "l_squirrel.h"
 | |
| #include <iostream>
 | |
| #include <asio.hpp>
 | |
| #include <spdlog/spdlog.h>
 | |
| #include <spdlog/sinks/stdout_color_sinks.h>
 | |
| #include <spdlog/sinks/basic_file_sink.h>
 | |
| 
 | |
| 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::string Ip = "192.168.200.27";
 | |
|     // std::string Ip = "127.0.0.1";
 | |
|     std::string Port = "65109";
 | |
|     std::mutex PackMtx;
 | |
| 
 | |
| public:
 | |
|     bool ConnectState = false;
 | |
| 
 | |
|     std::fstream file;
 | |
| 
 | |
| public:
 | |
|     Client(asio::io_context &io_context, std::string Ip, std::string Port)
 | |
|         : resolver(io_context),
 | |
|           socket(io_context)
 | |
|     {
 | |
|         endpoint = resolver.resolve(Ip, Port);
 | |
|         this->Ip = Ip;
 | |
|         this->Port = 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;
 | |
|             start();
 | |
|         } });
 | |
|     }
 | |
| 
 | |
|     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 (writeDataSize < 4)
 | |
|             return;
 | |
|         // 如果里面已经读了超过一半的大小了
 | |
|         if (writeDataSize >= 8192)
 | |
|         {
 | |
|             PackMtx.lock();
 | |
|             // 复制已读大小开始到结束到 开始  作用删除前已读大小的数据
 | |
|             std::copy(PackData.begin() + receivedDataSize, PackData.end(), PackData.begin());
 | |
|             // 将最后元素设置为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 || ((writeDataSize - receivedDataSize - 4) < PackSize))
 | |
|             return;
 | |
|         char *StrBuffer = new char[PackSize];
 | |
| 
 | |
|         std::copy(PackData.begin() + 4 + receivedDataSize, PackData.begin() + 4 + PackSize + receivedDataSize, StrBuffer);
 | |
|         std::string Str(StrBuffer, PackSize);
 | |
|         delete[] StrBuffer;
 | |
| 
 | |
|         // 包数据大小读取的偏移 这次读了多少
 | |
|         receivedDataSize += (4 + PackSize);
 | |
| 
 | |
|         // std::cout << "包大小:  " << PackSize << std::endl;
 | |
|         // std::cout << "包内容:  " << Str << std::endl;
 | |
|         // std::cout << "收到了第:  " << TestCode << "个包" << std::endl;
 | |
|         // spdlog::info(Str);
 | |
| 
 | |
|         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(), PackSize);
 | |
|             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();
 | |
|     void Init(std::string Ip, std::string Port);
 | |
|     void Send(const SQChar *Pck);
 | |
|     void Logic();
 | |
|     void IntToByteLittle(unsigned char *b, int Count);
 | |
| 
 | |
| public:
 | |
| };
 |